merge会使得log错综复杂,但是会保留时间线
rebase会保持log为一条线,但是最后log上的节点不是最原始commit的节点,不保留时间线。当前分支的节点会被复制到rebase 分支的节点后面,然后将原始的commit节点删除。
假设现在本地仓库中有两个分支:master分支和branch1分支,提交历史用图来表示如下
1. git merge
现在要合并dev_test1到dev分支,如果使用merge,命令如下:(dev是父分支、dev_test1是子分支或者dev是源端分支、dev_test1是相对应的本地分支,这两种场景都是这样)
git checkout dev
git merge dev_test1
执行完上述两行命令之后,查看log,会产生如下结果:
$ git log --oneline --graph -4
* 2b22529 Merge branch 'dev_test1'
|\
| * 39b3ec9 add file ttt.txt dev_test1
* | d0ff983 modify myTest.txt 1 dev
|/
* 0d5f874 modify myTest.txt
此时dev上提交历史如下:
可以看到,日志就出现了两个分支,而且查看详细日志会发现log节点会根据时间自动排序,这样会产生两个问题:其一为log特别复杂,各种合并节点、分支线等等;其二为某分支合并过来的日志会被按时间分散,很难再master上查找某个分支的完整提交日志。
2. git rebase
如果使用rebase,【git rebase A B 代表寻找到A和B的共同祖先,然后将这段期间B的提交加到A的后面。通常B被省略,代表当前分支】
2.1 场景1(dev为父分支,dev_test1是基于dev的子分支),先拉取dev到dev_test1
$ git checkout dev_test1
$ git rebase dev
First, rewinding head to replay your work on top of it...
Applying: add file ttt.txt
此时再查看log:
$ git log --graph --oneline -4
* bbd022c (HEAD -> dev_test1) add file ttt.txt
* d0ff983 (origin/dev, dev) modify myTest.txt 1
* 0d5f874 (origin/dev_test1) modify myTest.txt
* 6ea82bf modify myTest.txt
确认之后,执行git push推送至远端。此时dev_test1上的日志就是一条线了,本分支的节点被重新创建新增到rebase的那个分支节点后。
之后在切回dev分支,执行rebase dev_test1
$ git checkout dev
$ git rebase dev_test1
$ git log --oneline --graph -4
* bbd022c (HEAD -> dev, origin/dev_test1, dev_test1) add file ttt.txt
* d0ff983 (origin/dev) modify myTest.txt 1
* 0d5f874 modify myTest.txt
* 6ea82bf modify myTest.txt
可以看到,在dev_test1执行git rebase后的节点bbd022c,现在是跟在dev分支节点后的,这样就保证了子分支的节点会出现在父分支的后面。如果直接在dev分支执行git rebase dev_test1,此时dev_test1上的节点会跑到dev前边去,不大合理
2.2 场景2,dev与origin dev间执行rebase。
我切了一个origin/dev对应的本地分支dev
$ git checkout dev
然后再本地有一条修改,可以看到远端dev的位置在bbd022c节点上
$ git log --oneline -4
9aec5ac (HEAD -> dev) modigy myTest.txt
bbd022c (origin/dev,origin/dev_test1, dev_test1) add file ttt.txt
d0ff983 modify myTest.txt 1
0d5f874 modify myTest.txt
而此时其他人往远端分支push了一条记录,我们现在想要提交修改到远端。首先把远端的变化fetch到,注意一定要用fetch,不能使用git pull(因为它=git fetch+git merge,或者使用git pull -r也可以,它=git fetch + git rebase),这样的话就执行了merge,本地分支的log就出现了两条线)
$ git fetch
$ git log --oneline -4
bbd022c (HEAD -> dev, origin/dev_test1, dev_test1) add file ttt.txt
d0ff983 modify myTest.txt 1
0d5f874 modify myTest.txt
6ea82bf modify myTest.txt
查看日志,可以看到现在远端的 origin/dev已经不再bbd002c节点上了,此时我们执行rebase
$ git rebase origin/dev
First, rewinding head to replay your work on top of it...
Applying: modigy myTest.txt
$ git log --oneline -4
7d2c7c5 (HEAD -> dev) modigy myTest.txt
8c1a80f (origin/dev) modify ttt.txt
bbd022c (origin/dev_test1, dev_test1) add file ttt.txt
查看日志发现,此时origin/dev的最新节点为8c1a80f,而我们自己修改的节点为7d2c7c5,然后再git push,提交到远端
$ git push
$ git log --oneline --graph -4
* 7d2c7c5 (HEAD -> dev, origin/dev) modigy myTest.txt
* 8c1a80f modify ttt.txt
* bbd022c (origin/dev_test1, dev_test1) add file ttt.txt
* d0ff983 modify myTest.txt 1
可以看到现在log就只有一条线了。
但是你虽然将这一条线push到了远端,那其他人怎么同步你的修改呢?也是一样的,执行git rebase
$ git rebase origin/dev
First, rewinding head to replay your work on top of it...
Fast-forwarded dev to origin/dev.
$ git log --oneline --graph -4
* 7d2c7c5 (HEAD -> dev, origin/dev) modigy myTest.txt
* 8c1a80f modify ttt.txt
* bbd022c (origin/dev_test1) add file ttt.txt
* d0ff983 modify myTest.txt 1
刚刚提交那条记录的人,直接执行git rebase之后,本地分支和远端分支就在同一个节点上了