变基,听这个名字有没有奇怪的感觉。从字面意思理解就是改变根基的意思。
什么是根基
先看master分支历史:
$ git log --graph --oneline
* fa08267 (HEAD -> master) 添加
* 5948d84 添加f
* 278629a 添加e
* 9a32699 添加d
然后我们创建了一个新的分支dev
$ git checkout -b dev
dev的历史:
$ git log --oneline
fa08267 (HEAD -> dev, master) 添加
5948d84 添加f
278629a 添加e
9a32699 添加d
这个时候master与dev的历史是一样的。
master与dev都指向了fa08267,dev后续要基于fa08267进行修改和提交,那么fa08267就是它的根基。
接下去dev提交了两次:
$ git commit -am "删除b"
$ git commit -am "修改c"
$ git log --oneline
ee26e4f (HEAD -> dev) 修改c
0ddcf18 删除b
fa08267 (master) 添加
5948d84 添加f
278629a 添加e
9a32699 添加d
master也提交了1次:
$ git commit -am "添加i"
$ git log --oneline
907d5cd (HEAD -> master) 添加i
fa08267 添加
5948d84 添加f
278629a 添加e
9a32699 添加d
再看master和dev的历史是这样的:
变基与合并
如果现在dev要与master合并,一种方式是用git merge,另一种是就git rebase,下面我们对比一下两种执行结果有什么不同。
先在dev分支上检出另一个分支dev1
$ git checkout -b dev1
这时候dev与dev1是完全一样的两个分支
接下来用dev分支变基
$ git checkout dev
$ git rebase master
$ git log --graph --oneline
* ca39653 (HEAD -> dev) 修改c
* bbc7ec6 删除b
* 907d5cd (master) 添加i
* fa08267 添加
* 5948d84 添加f
* 278629a 添加e
* 9a32699 添加d
从历史可以看到dev的两次修改已经从fa08267之后变成了master最新提交907d5cd之后,也就是本来是在fa08267基础上修改,现在变成了从907d5cd基础上修改。这就是变基(改变了根基)。
接下来dev1与master合并
$ git checkout dev1
$ git merge master
$ git log --graph --oneline
* 3952e4a (HEAD -> dev1) Merge branch 'master' into dev1
|\
| * 907d5cd (master) 添加i
* | ee26e4f 修改c
* | 0ddcf18 删除b
|/
* fa08267 添加
* 5948d84 添加f
* 278629a 添加e
* 9a32699 添加d
从历史看,dev两次修改之后添加了master分支的907d5cd,合并形成了新的 3952e4a
从结果(ca39653 和 3952e4a)看,虽然变基与合并是完全一样的,但是变基的历史比合并的历史看起来要干净简洁。 这正是变基美妙的地方。
撤消变基
撤消变基的方法同样也可以用于撤消合并
git rerlog + git reset --hard
$ git reflog
0497f5b (HEAD -> dev) HEAD@{0}: checkout: moving from dev1 to dev
ee26e4f (dev1) HEAD@{1}: reset: moving to HEAD@{11}
0497f5b (HEAD -> dev) HEAD@{2}: checkout: moving from dev to dev1
0497f5b (HEAD -> dev) HEAD@{3}: checkout: moving from dev1 to dev
fa08267 HEAD@{4}: checkout: moving from master to dev1
907d5cd (master) HEAD@{5}: checkout: moving from dev to master
0497f5b (HEAD -> dev) HEAD@{6}: rebase (finish): returning to refs/heads/dev
0497f5b (HEAD -> dev) HEAD@{7}: rebase (pick): 修改c
4e0e81e HEAD@{8}: rebase (pick): 删除b
907d5cd (master) HEAD@{9}: rebase (start): checkout master
ee26e4f (dev1) HEAD@{10}: checkout: moving from master to dev
907d5cd (master) HEAD@{11}: commit: 添加i
fa08267 HEAD@{12}: checkout: moving from dev to master
ee26e4f (dev1) HEAD@{13}: commit: 修改c
0ddcf18 HEAD@{14}: commit: 删除b
fa08267 HEAD@{15}: checkout: moving from master to dev
fa08267 HEAD@{16}: checkout: moving from test1 to master
fa08267 HEAD@{17}: checkout: moving from master to test1
fa08267 HEAD@{18}: commit: 添加
5948d84 HEAD@{19}: commit: 添加f
278629a HEAD@{20}: commit: 添加e
9a32699 HEAD@{21}: commit: 添加d
$ git reset --hard HEAD@{13}
$ git log --graph --oneline
* ee26e4f (HEAD -> dev, dev1) 修改c
* 0ddcf18 删除b
* fa08267 添加
* 5948d84 添加f
* 278629a 添加e
* 9a32699 添加d
* e1d9937 修改c
* bbf16a1 添加了c
* 7cd0720 修改b
* ef43f31 添加了d