Git merge ? 还是 Git rebase ?

在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。那么应该使用 Git merge 还是 Git rebase 呢?

关于这个问题,程序员之间的争论似乎从来都没有停止过!持不同观点的人,各有各的理由,并且很难说服对方!所以一个折中的回答似乎应该是:

关于应该使用 Git merge 还是 Git rebase ,需要根据具体情况来具体分析。

这句话当然没错,但是本文,我想再深入聊一下:到底(更)应该使用 Git merge 还是 Git rebase 。


一个比较有意思的现象是:在怎么使用 Git 上面,程序员之间总是有很多争论和相悖的观点,从 Git 分支(开发分支、测试分支、线上分支、feature 分支等)应该如何创建、如何合并、什么时候合并等,到应该使用 Git merge 还是 Git rebase ,程序员之间的争论从来没有停止过,甚至很难达成一个基本的共识,为什么呢?

根本原因,还是在于 Git 使用起来太灵活了,Git 的命令太多了,达到同一个目的可选择的方式太多了,而不同公司不同部门,其项目规模差异巨大,导致不同公司/部门的开发者使用 Git 的方式也差别巨大。所以还是那句话:具体怎么使用 Git 还是要根据公司内部具体情况而定。工具的使用,没有绝对的标准,只要你用的顺手就行。


先看一张图来回顾一下 Git merge 和 Git rebase 的差别:

merge 的使用比较简单,在分支合并的时候如果可以使用 fast-forward 则 Git 默认会使用 fast-forward(可以使用 –no-ff 参数禁止 fast-forward),否则 Git 会使用两个分支的末端所指的快照、以及这两个分支的公共祖先,做一个简单的三方合并,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。

rebase,re 即“重新”的意思,rebase 就是重新设置基础节点的意思。当我们说将 dev 分支变基到 master 上时,其实就是将 master 上最后一个节点当作 dev 分支的新的基点,然后将 dev 分支上位于 dev-master 共同结点之后的提交,添加到新的基点之后。这里有一个注意点,如上图变基之后新的 E’、F’、G’ 和原先的 E、F、G 节点的哈希值是不同的。正因为如此,所以使用 rebase 命令有一个黄金法则:

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。

简单来说就是,你要 rebase 就 rebase 你自己的分支,别 rebase 别人的分支,特别是多人协调开发时的主干分支。因为你一旦 rebase 了别人的分支或主干分支,则其实已经修改了别人分支或主干分支上相关节点的 commit 信息,但别人本地的 commit 节点还是原先的 commit 信息,最终在提交记录中你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。

我的看法:

merge 命令使用难度低于 rebase,rebase 如果使用方式有误,会导致非常严重的后果,merge 命令则安全的多。

使用 merge 命令会保留所有 commit 的历史时间和修改,每个开发者的每一次提交内容、提交时间都可以被追溯到,这也是很多人支持使用 merge 的原因。但也正是这个原因,相当多开发者会把没有开发完、不完整的临时文件给 commit 了,一次小的功能迭代开发,可能会有几十上百次 commit,其中很多 commit(比如写到一半的方法、没有自测而编译报错的代码、批量重命名、修改一个变量名、增加一条日志等等)要么是没有意义的、要么是可以被合并成一个的,这些 commit 会造成提交历史混乱且难以进行代码 review ,这种混乱的、交叉的提交历史,我相信是没有人乐意去里面翻代码的,而且也基本不可能进行代码 review。

git 的每个 commit 都应该代表一个完成的逻辑,git 能记录每次 commit 的历史时间和修改,但不能把 git 的 commit 当作一个『文件备份』的功能来使用。

rebase 能够保持主干分支的干净(一条线),不会像 merge 那样产生很多混乱交叉的提交记录,方便代码 review ,rebase 使用门槛高于 merge,如果 rebase 的使用方式有误,会导致非常严重的后果,而 merge 则几乎不会导致这种严重的后果。

我觉得 merge 和 rebase 最主要的差别有两点:第一点,是否会对提交历史进行修改。第二点,是否需要保持干净清晰一条直线的提交历史。

所以最终,我们需要思考的一个问题是:提交历史,意味着什么?

如果你认为提交历史就像『快照』一样,是某一时刻代码修改的快照,不允许被修改,那使用 merge 更好。

如果你认为提交历史,就像写文章时的草稿,在文章写完之后,草稿就没有用了,草稿可以根据情况被修改或删掉,以使提交记录更加清晰方便后人理解,那么使用 rebase 和 filter-branch 更好。

所以使用 merge 还是 rebase 还是得根据具体情况而定,现实中一般是由技术 Leader 决定,需要综合各方面的因素。

完。

码先生
Author: 码先生

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注