设想这样的场景,
周一,我们为了开发一个新功能,从master上拉出来一个feature001.R1分支,进行功能开发。
周二,master上发现bug,由其它同事从master上拉出一个bug001.R1分支,进行bug修复。
周三,bug修复完成,合并回master。
周四,我们的功能开发完成,此时要如何把feature001.R1合并到master?
如果直接切换到master进行 merge 操作,可以完成合并,但是合并之后,在master分支执行下面的命令,查看提交历史记录
> git log --graph --pretty=oneline --abbrev-commit
会看到下面的图形
* e4d20d9 Merge branch 'feature001.R1'
|\
| * f72412a 功能开发-001,v2
| * b943b68 功能开发-001,v1
* | 991f559 修复bug-001,v2
* | 2482dcd 修复bug-001,v1
|/
* 71df2e0 init
看上去commit记录不太干净,受分支上的提交记录污染了。
出现这种情况,是因为拉出feature001.R1分支的从master基点已经落后了。
周四,功能开发完成时,先不要合并feature001.R1,而是:
1. 切换到master分支,执行`git pull`,将最新的master拉下来。
2. 切换回feature001.R1分支,执行 `git rebase master`,这是干什么呢?简单地说,它重置了feature001.R1分支的基线,就是将拉出feature001.R1分支的master基点移动到master的最新位置,就好像先发现bug,创建bug分支、解决bug、合并bug分支到master,然后才拉出功能分支feature001.R1,这个过程中,可能会有冲突,需要解决冲突,再rebase continue...。
实际上,rebase背后做了什么?git是如何移动基点的呢?
首先,git会把feature001.R1分支上的所有commit取消掉;
其次,将feature001.R1分支上被取消的操作制作成 patch 文件,保存起来('.git/rebase'目录);
然后,把feature001.R1分支更新到最新的master分支,相当于将最新的master分支合并到feature001.R1,但不产生任何合并记录,也相当于在最新的master分支上重建了feature001.R1分支。
最后,把上面保存的 patch 文件应用到 feature001.R1分支上,此过程可能产生冲突。
3. 切换到master分支,merge合并 feature001.R1分支
这样完成合并之后,就提交历史就不会有分叉了,
> git log --graph --pretty=oneline --abbrev-commit
* 15892dc 功能开发-002
* a3cb265 修复bug-002,v2
* 958880e 修复bug-002,v1
* e4d20d9 Merge branch 'feature001.R1'