Git合并策略之rebase v.s. merge

·  阅读 2761
Git合并策略之rebase v.s. merge

git rebasegit merge是我们日常开发中使用的两种分支合并策略,最近团队也在代码库的分支管理上有一些要求,所以记录一下这两种合并策略的优缺点和使用场景,便于日常的代码库管理。

概述

关于git rebasegit merge,两者所处理的问题是相同的,就是将一个分支上的改动集成到另一个分支上,区别在于他们实现的方式不同。

考虑如下的工作场景:

你要在当前项目开发一个新的功能点,于是基于main分支拉出了一个feature分支开始进行开发。而与此同时你的同事开发了另一个新的功能or修复了一个bug并且合并到了main分支,于是main分支在你开发的过程中也有了新的提交,这就导致分支的提交历史开始分叉

未命名文件.png

当feature分支开发完成要合入main分支时,就需要考虑使用merge还是rebase进行合入。

Merge

merge选项是最简单的合入方式,当我们要将feature分支合入main分支时,只需要首先在本地切换到main分支,然后执行git merge命令即可:

git checkout main
git merge feature
复制代码

也可以使用一行命令完成:

git merge main feature
复制代码

之后将本地的修改通过git push推送到远端仓库即可。

执行git merge后会在main分支产生一个“merge commit”,分支状态如下:

未命名文件 (1).png

merge的好处在于它是一个非破坏性的操作。因为在执行merge后原本的分支(此处指feature分支)并没有被改变

相对的,merge的缺点就在于每次合并分支都会产生一个无关的合并提交。如果提交的次数较多,这些无关的合并提交会污染分支的历史记录,在多人协作时可能会让人难以理解项目的提交历史。

Rebase

和merge选项相似,我们也可以使用rebase命令将feature分支合并到main分支上, 使用如下命令:

git checkout feature
git rebase main
复制代码

rebase命令会将整个feature分支以main分支的顶端(head所在的提交)为基准,将所有的新的提交合入。但是,和merge commit不同,rebase命令会通过为每次提交创建全新的提交来重写整个项目的历史

此时feature分支的本地状态如下:

未命名文件 (2).png

通过rebase操作后,我们本地的feature分支上的提交都是基于main分支的提交后生成的,此时再切换到main分支执行merge操作:

git checkout main
git merge feature
复制代码

由于rebase后的feature分支和main分支不会有冲突,因此直接执行fast-forward式的merge,不会产生merge commit,再执行git push推送到main分支的远端即可。

rebase的最大好处就是分支的提交历史会非常清晰。首先它不会产生不必要的merge commit,其次分支的提交历史不会产生分叉,只有一条十分清晰的线性历史,可以清楚的看到每次提交。

但是rebase的特性也造成了一些风险。必须要牢记的一点就是,不要在公共分支上执行rebase操作!在多人合作的分支上执行rebase操作很有可能将分支历史重写,甚至将其他人提交的代码丢失,这是很危险的操作。因此rebase前一定要好好确认

其次,rebase不像merge操作会保留合并时的上下文,实际上rebase后产生的提交已经和原本的提交不同(commit id是不同的),提交顺序也很可能产生错乱,这时就没办法判断合并时的上下文。如果我们的代码库主干分支中一直使用rebase进行合并,那么就很难判断某个版本上线进行了哪些代码更改。

冲突解决

多人协作中,最常遇见的问题就是合并过程中产生的冲突。

开发时修改文件,可能产生以下三种情况:

  • A和B修改了不同文件的代码;
  • A和B修改了同一个文件的代码,但不是同一个部分的代码;
  • A和B修改了同一个文件同一个部分的代码;

对于前两种情况,git会直接进行自动的合并,不会引起冲突。需要解决冲突的是第三种情况。

在使用git merge时,产生冲突后,我们需要针对冲突文件进行判断修改,保存后再依次执行git addgit commitgit push命令即可。只需解决一次冲突就可以完成merge操作。

git add filename
git commit -m "commit"
git push
复制代码

而在使用git rebase时,如果产生冲突,则需要解决冲突保存文件后执行:

git add filename
git rebase --continue
复制代码

而此时也有可能执行git rebase --continue后又一次的产生冲突。那么我们就需要继续解决冲突(重复以上的步骤)直到不再产生冲突,就可以提交代码了。

总结

git mergegit rebase的对比如下:

优点缺点
git merge保留了原始分支的历史/保留了合并操作的上下文/只需解决一次冲突产生无关的merge commit,次数较多会污染提交历史
git rebase提交历史清晰,保留线性提交历史没有合并上下文,commit id和提交顺序被修改,出现问题难以定位/可能需要多次解决冲突

两者各有优缺点,所以我们应该根据团队的规模、开发模式来选择不同的策略。个人认为,多人协作时每个人都应该拉出属于自己的feature分支进行开发,开发完毕后通过rebase统一合入开发环境的分支。因为开发过程中分支是比较活跃的(通常会很频繁的合入代码、部署dev环境等等),rebase合入能够保证每个功能的完整性,并且保持线性历史,同时也不用太担心操作失误的风险。

而在进行提测上线等节点的操作时,建议使用merge操作,可以留下合并分支的上下文,清楚的知道本次提测or上线操作所产生的所有变更,当出现问题时也更方便溯源。

分类:
开发工具
标签:
收藏成功!
已添加到「」, 点击更改