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

举报
gentle_zhou 发表于 2022/02/20 16:05:53 2022/02/20
【摘要】 rebase merge是相对来说最优解。可以自行手动选择合并压缩哪些分支(pick 与 fixup),且不会改变commit作者信息,commit提交记录也很清晰。

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

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

先上总结,普通的基本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中);用 g i t l o g 命令可以查看到所有的这些提交历史记录。以上图为例,我们作如下操作: git log命令可以查看到所有的这些提交历史记录。 以上图为例,我们作如下操作: git checkout branchC //切换到分支C
$gti merge branchD //把分支D并入分支C

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

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

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

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

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

我们可以看到,分支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操作,
    g i t c h e c k o u t b r a n c h D / / 切换到分支 D git checkout branchD //切换到分支D git rebase -i branchC //重新定义分支D的参考基准为分支C
    上面这个命令的-i 参数用来手动调整commit历史,会弹出一个文本编辑框(下面是我拿一个实际的分支来做参考)
    image.png

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

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

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

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

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

image.png

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。