大部分开发者都有遇到过该用 Merge 还是 Rebase 的问题,网络上的各种相关介绍几乎都认为:“不要使用 Rebase,因为它会产生各种问题”。这里我将介绍 merge 和 rebase 的概念,为什么你应该(或者不应该)使用它们,以及怎么用。

Git Merge 和 Git Rebase 目的相同,它们都是把不同分支的提交合并到一起。虽然最终目的是一致的,但是其过程却颇为不同。了解它们之间的区别之后,你会成为一个更出色的开发者。

Git 社区对这个问题有很大争论,一些人坚持应该只用 rebase,另外一些人认为只用 merge,事实上两种方式各有优势。

Git Merge

对于使用版本控制系统的开发者来说,Merging 是常规操作。不管创建的分支是用来测试、修复 bug,还是别的什么原因,可能都会需要把分支的提交 merging 到其它的分支上。具体来说,merging 就是把源分支的提交放到目标分支里面。在这个过程里,只有目标分支改变,而源分支保持原样。

2-2
Merge Master -> Feature branch

优点

  • 简单易上手
  • 保留了提交历史和时间次序
  • 保留了分支的结构

缺点

  • 提交历史被大量的 merge 提交污染了
  • 使用 git bisect 调试变得更困难了

怎样做

使用 checkoutmerge 命令把 master 分支 merge 到 feature 分支。

$ git checkout feature
$ git merge master

(or)

$ git merge master feature

这将会在 feature 分支上创建一个新的 “Merge 提交” 用来保留所有分支的记录。

Git Rebase

Rebase 是合并两个分支的另一种方式。Rebase 把所有的提交压缩成一个 “patch”。然后把 patch 添加到目标分支里。

和 merging 不同,rebasing 清除了历史,因为它完全是从一个分支转移到了另一个分支。在这个过程中,多余的记录被移除了。

Rebases 的提交从顶部按次序向下排列,而 merges 则自下而上。
3-2
Rebase feature branch into master

优点

  • 把复杂的历史变成优雅的提交线
  • 操作单个提交变得很简单(比如,reverting)
  • 避免了庞大的仓库、海量的分支以及烦人的 merge 提交
  • 线性合并清除了中间的无用提交,对于 DevOps 团队来说是个好消息

缺点

  • Rebase 后 feature 分支间的上下文模糊了
  • 在团队里 rebasing 公共分支是高风险的事
  • 工作变多了:feature 分支需要经常更新
  • Rebasing 到远程分支需要 force push。最大的问题是人们经常已经 force push 了,才发现忘记了设置 git push 默认值。结果本地远程所有同名的分支都进行了更新,清理起来很要命。
如果你 rebase 出错并且很不幸重写了历史,很棘手,所以一定要明白操作的意义。

怎样做

下面的命令把 feature 分支 rebase 到 master 分支上。

$ git checkout feature
$ git rebase master

它把整个 feature 分支的提交移动到了 master 分支上。通过给每个源(feature) 分支创建了一个 brand 来 re-writing 项目的历史。

Interactive Rebasing

这个命令可以在移动 commit 前改变它们。这比普通的 rebase 更加强大,它提供了对分支提交历史的完整控制。另外,在合并 feature 分支到 master 前,还可以用它来清理混乱的提交历史。

$ git checkout feature
$ git rebase -i master

他会打开编辑器列出将要被移动的提交。

pick 22d6d7c Commit message#1
pick 44e8a9b Commit message#2
pick 79f1d2h Commit message#3

它清晰地展示了分支在 rebase 后的样子。通过重新调整,提交历史可以变成任何你想要的样子。如,可以把 pick 换成 fixup , squash , edit 等命令。

4-2

选哪个

所以,哪个是最好的?有没有专业的建议呢?

很难明确告诉你该选哪一个,毕竟每个团队的情况不同。但还是有章可循。

团队在制定他们的 Git rebase vs. merge 策略时需要考虑很多问题。事实证明,工作流之间并无明显的高下之分,一切都取决于团队情况。

选择更直白的 rebasing 还是历史可塑性更强的 merging,要考虑团队对 rebasing 的了解情况以及 Git 熟悉程度。

最后,决定使用 merging 还是 rebasing 还应该考虑到分支策略(阅读这篇文章来了解分支策略)。团队有必要制定一个合适的分支策略。

我的建议

随着团队增长,通过 merge 策略很难管理和追踪到每个提交。为了提交历史更清晰、更易于理解,使用 Rebase 是一个明智、高效的选择。

下面是针对不同环境的建议,可以最大限度地发挥 Rebase 的优势:

  • 本地开发:如果你没有和别人协同工作,你应该使用 rebasing 而不是 merging ,这样历史记录会很清晰。如果你已经从仓库拉取了你的个人 fork,并且不准备和别的开发者一起工作,在分支 push 前 rebase 也是可以的。
  • 你的代码准备好了被 review: 你创建了 pull request。别人正在 review 你的代码,可能把它拉到了本地 review。如果这样,你最好别 rebase 你的代码。你应该创建一个 “rework” 提交来更新你的 feature 分支。它会让 pull request 的可塑性更强,也能避免历史突然丢失。
  • review 已经完成并且已经准备好了合并到目标分支。恭喜!你就要删除你的 feature 分支了。由于别的开发者不需要拉取、合并这些更改,这是你清理记录的好机会。你可以改写记录,折叠原始提交、“pr rework” 提交和 "merge"提交,使之成为一整个清晰的提交。作为可选,你还可以给这些提交创建一个明确的 merge,这样做实际上很有用。它会记录 feature 并入master 的时间。

结论

希望这些解释能让你对 Git merge 和 Git rebase 更了解。Merge vs rebase 策略之争永无止境。但愿这篇文章可以帮助你扫清迷惑,找到一个适合自己的团队的方向。

原文链接:An introduction to Git merge and rebase: what they are, and how to use them,作者:Vali Shah