【git系列】三种合并分支的操作-merge, squash merge & rebase merge

先前我写了篇文章,介绍了如何把别的分支的改动内容同步更新到自己的分支,文章特别针对了“如果我们只需要同步部分提交,就只需要$git cherry-pick”的情形,而本文则是做一个补充,针对于同步整个分支$git merge的3种操作。
假设我们有如下的两个分支C和D,都是基于主分支上的B点拉出来的;分支C作为主分支有2个提交C1, C2;而分支D上是我们做的修改,有3个提交D1, D2, D3。

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第1张图片

同时分享一个word小技巧:word-文件-选项-显示-段落标记去掉勾号,表格里的小箭头就会去掉;否则,这些“密密麻麻”的小箭头会很影响美观:

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第2张图片

先上总结,普通的基本merge尽量不要用;当要合并的分支D都是自己开发的且都是些微小的改动用squash merge;当需要自行手动选择合并压缩哪些分支(pick 与 fixup),且不会改变commit作者信息,commit提交记录也很清晰的时候用rebase merge。(一言以蔽之,rebase merge yyds!)

【git merge】
最基本的合并分支操作,就是把分支A上所有的commit历史原封不动地拷贝至目标分支B上,并且会生成一个新的Merge Commit(一个“空”的commit-我们这里叫它MC,里面没有任何代码改动,只有一个提交记录-merge了D至C中);用git log命令可以查看到所有的这些提交历史记录。 以上图为例,我们作如下操作:gitlog命令可以查看到所有的这些提交历史记录。以上图为例,我们作如下操作:git checkout branchC //切换到分支C
$gti merge branchD //把分支D并入分支C

得到的完整的提交历史记录如下:

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第3张图片

从上图可以看出,基本merge操作保留了所有的操作记录(一些commit可能只是很微小的改动,比如改了名字,修改了checkstyle的一些缩进问题)且会生成一个不必要的commit-MC.

【git squash merge】
一开始看到squash,第一反应是美洲南瓜。。。

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第4张图片

然后再去理解了下,应该是压缩/挤压的意思,那么顾名思义就是把分支D上的众多commit压缩成一个,再合并到分支C上。
以一开始的图为例,我们作如下操作:
git checkout branchC //切换到分支CgitcheckoutbranchC//切换到分支Cgti merge --squash branchD //把分支D上所有commit压缩
$git commit -m “squash merge” //上一步压缩之后,把所有的改动合并,放在了本地;需要我们手动提交到分支C上

得到的提交历史记录如下:

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第5张图片

我们可以看到,分支D中的D1, D2, D3都被压缩成了commit D;而且因为是我们在分支C上commit了D,我们相当于把先前的D1, D2, D3的作者都变成了自己(提交者发生了变化;如果分支D只有自己在开发,倒也还好;要是我们是从D2开始接手,那后期找维护人责任人就是你了)
因此,squash提交有好处就是我们可以把一些很小的改动的提交合并起来,避免整个分支的提交历史过于繁琐复杂;缺点也明显,就是会改变commit作者信息,对于后期维护追溯有难度(当然如果整条分支都是你开发的,且都是些微小的改动,squash是个不错的选择)。

【git rebase merge】
而rebase merge则是可以完美解决squash改变commit作者信息的问题同时可以合并commit历史的操作。rebase其实可以拆分开来,re + base,即重新定义分支的参考基准。
rebase merge 分为两步来完成:

1. 执行rebase操作,

git checkout branchD //切换到分支DgitcheckoutbranchD//切换到分支Dgit rebase -i branchC //重新定义分支D的参考基准为分支C
上面这个命令的-i 参数用来手动调整commit历史,会弹出一个文本编辑框(下面是我拿一个实际的分支来做参考)

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第6张图片

上面的b54e8bf就相当于是D1,95fa074就相当于是D2,f111927就相当于是D3。
我们可以在文本编辑框里对这些commit进行选择调整,看看是否要合并。比如我们的D2只是对D1的一个微小的调整(函数名字没有遵从camelStyle),可以不用显式地展示,那我们就把D2的pick改为fixup即可:

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第7张图片

那么我们rebase之后的分支C 的commit历史记录就变为:

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第8张图片

注:我们在执行git rebase的时候,可能会出现冲突的问题,此时需要我们手动去解决冲突问题。就如我在文章【git系列】add commit pull(rebase) push四步曲里说的,“若有冲突文件,去修改冲突,$git add, git rebase --continue 来合并冲突,线性地连接本地分支与远程分支”;如果中途想要放弃rebase操作,gitrebase−−continue来合并冲突,线性地连接本地分支与远程分支”;如果中途想要放弃rebase操作,git rebase --abort命令可以回到rebase之前的状态,如下图可以看到,abort之后没有啥提示,但是分支状态改变了。

2. 接着我们再执行merge操作,把分支D合并到分支C:

$git checkout branchC  //切换到分支C
$git merge branchD  //把rebase之后的分支D并入分支C

【git系列】三种合并分支的操作-merge, squash merge & rebase merge_第9张图片

因此,rebase merge是相对来说最优解。
可以自行手动选择合并压缩哪些分支(pick 与 fixup),且不会改变commit作者信息,commit提交记录也很清晰。

转载自华为云社区,文章作者 gentle_zhou

你可能感兴趣的:(git,github)