文章

对比分支管理中的merge与rebase

介绍在合并分支时使用`git merge`指令和`git rebase`指令的区别,并介绍多人协作中使用`rebase`需要遵守的黄金准则,以及若不遵守有怎样的后果

对比分支管理中的merge与rebase

关于Git的基本操作讲解,参考我对应的博客:Git入门基础知识汇总

一、对比rebase与merge

  • rebase又称变基,其和merge都是用于合并分支的指令,但二者的合并方式有着较大的差异
    • git merge
      • 完整保留所有提交记录及其分支结构,并保持提交ID不变
      • 可追溯性较高,但复杂的结构会导致难以进行代码审核与漏洞追查
    • git rebase
      • 会在合并后以分支的共同根提交记录作为基底,将分支结构融合重组为一条线性结构,这会导致某些提交ID的改变
      • 使得提交记录较为整洁,但当多人协作时若不遵循黄金法则,则会导致仓库严重混乱、空间浪费等问题

CompareMergeOrRebase.png

  • 如上图所示,其相当于是在feature分支上执行了git rebase develop,原有的记录C、D、E都被新建为新的分支变基到了B记录上,形成了一条线性结构,这条线性记录仍然归属于调用这条指令的feature分支上,develop分支仍保留原有的提交记录不变

二、搭建测试用例

  • 我在第一次提交中创建了下图的test.txt文件,提供了对Function-1Function-2A实现

CompareMergeOrRebaseP1.png

  • 此时创建一个新分支bran,然后进行如下修改提交
    • master分支上将Function-1的实现先后改为Implementation-XImplementation-XX
    • bran分支上将Function-2的实现先后改为Implementation-YImplementation-YY

CompareMergeOrRebaseP2.png

CompareMergeOrRebaseP3.png

CompareMergeOrRebaseP4.png

CompareMergeOrRebaseP5.png

三、进行merge会怎样

  • 此时切换到master分支上使用git merge bran进行合并(将bran合并到master上),结果如下图所示,可以看到所有的提交记录都被保留了下来,并且所有commit的ID编号都不会被改变

CompareMergeOrRebaseP6.png

四、进行rebase会怎样

  • 回退到cbe2319版本,然后切换到master分支上

CompareMergeOrRebaseBeforeTest.png

  • 调用git rebase bran指令后,我们需手动将被换基的提交记录逐一与新基进行桥接,体现为冲突的处理(即便前后被桥接的两个版本一模一样,没有冲突,也需要进行手动处理该过程)
  • 处理完毕后执行git add暂存,然后使用git rebase --continue表示完成桥接(实际上这个过程就相当于创建了一个新的提交记录),然后就可以继续下一个提交记录的桥接了,直到所有被转移的提交记录都被处理完毕,他们在这个过程中被创建为新的提交记录
  • 我的测试用例中的master上仅有两个需要被转移的提交记录,所以仅需进行如下的两次处理

CompareMergeOrRebaseConflictP1.png

CompareMergeOrRebaseConflictP2.png

  • 完成上述两步后即完成了整个变基合并流程,由于我们是在master分支上执行的git rebase bran指令,所以最终这条线性的记录是保存在master分支上的

CompareMergeOrRebaseConflictP3.png

  • 分支master中除了基底0b4e138记录未被改变ID,其余两条则是被新建为了新的相同信息的提交记录变基到了另一个分支bran的最新提交记录上(可以使用git reflog来寻找原有的提交记录,而不是使用git log
  • bran分支的提交记录并未被改变,如下所示,bran仍维持在其原本最新的提交记录版本

CompareMergeOrRebaseConflictP4.png

五、黄金准则

  • 黄金准则指的是多人开发场景下,使用rebase时必须遵守的一个规范
1
2
>> "No one shall rebase a shared branch"
>> "不应当在共享的分支上执行git rebase another_branch指令操作"
  • 什么是共享的分支?如下图所示,两位开发者Bob和Anna都需要在feature分支上进行修改,那么feature分支就是共享分支
  • 可以看到下图中的Bob违反了黄金准则,此时Bob还未将修改推送到远程仓库,所以暂未发生问题,他的本地仓库中原先D记录的ID已经被新记录D’替代了,而Anna的本地仓库的D未发生改变,这就埋下了隐患,待我们逐步分析Bob这样做的严重后果

黄金准则P1.png

  • Bob将他的本地仓库推送到远程仓库后,远程仓库就如下图所示,当Anna此时也想要推送时,就需要先进行同步

黄金准则P2.png

  • Anna执行git pull feature指令后,自己的本地仓库就会被变成下面这个鬼样子,但是冲突确实解决了,可以进行推送操作

黄金准则P3.png

  • 假设Anna此时确信Bob会遵守黄金准则而不检查的话,那么在她将此时的本地仓库直接推送到远程仓库的话,那么远程仓库也会变成这个鬼样子,乱七八糟不说,并且由于存在大量重复的提交版本,还会导致远程仓库空间的浪费

黄金准则P4.png

  • 这还仅仅是两个人协作中发生的rebase误用,尚且如此严重,此时若出现第三个共享feature分支的人想要将其实现的F推送到远程仓库,就需要先拉取,拉取后就变成了下图的样子

黄金准则P5.png

本文由作者按照 CC BY-NC-SA 4.0 进行授权