前言
上一篇文章中,讲了在 git merge 的两种模式下分支是如何合并的。而在 git 中,除了 merge 命令,rebase 也是用于分支合并。那么,merge 和 rebase 又有什么不同呢。
merge
git merge 是一种用于合并两个分支历史的操作,它通过创建一个新的合并提交(merge commit),将两个分支的历史记录保留下来。这种方式不会改变任何一个分支的历史,只是在两个分支的基础上生成一个共同点。
在 merge 中,如果只在 dev 分支上做变更,而 master 分支不动,即在 dev 全包含于 master 的情况下,将 dev 分支合并到 master 分支会出现两种情况。
一种是 fast-forward 模式,使用 git merge 会自动使用这种模式。
如图,快进模式就不会生成新的 commit 信息,而是将 dev 的提交信息直接挪到 master上。而第二种 no-fast-forward 模式就会生成新的提交信息。
在 merge 时,使用 --no-ff 使用非快进模式。
代码语言:bash复制git merge dev -m'master4' --no-ff
如下图,在 merge 的同时又相当于做了一次 commit。
接着我们看看 rebase 是如何合并分支的。
rebase
git rebase 是另一种合并分支的方式,它通过将一个分支的提交移到另一个分支的基础上,重新应用这些提交。与 git merge 不同的是,git rebase 不会创建合并提交,而是将两个分支的提交历史线性化,重新排列提交记录。
和上面 merge 的前置条件一样,在 master 中有三次 git 提交记录,在此基础上,我们创建 dev 分支,然后变更文件再次提交一次。这时我使用 rebase ,将 dev 分支合并到 master 分支。
这个结果就和 git merge 的 fast-forward 模式一样,不会生成自己的提交信息,而是使用 dev 分支的提交信息。
但是在多人协作的开发中,很少有这种全包含的情况,基本上就是从一个 commit 的基点拉出分支,然后各自开发各自的,最后开发完成进行合并。
merge 合并
回退到合并前的状态,master 和 dev 分支都基于第三次提交之后再做变更。这里要注意的是:不要修改同一文件,否则会引发合并冲突。这时候两个分支提交信息如下图(绿色是master)。
这时候我执行 git merge 合并分支。因为 master 和 dev 两个分支在同一个基点之后,都有各自的提交历史,这时 git merge 合并分支,就会生成一个新的 commit 信息,然后 master 将 HEAD 指向最新的这个提交。
rebase 合并
再次回退到 merge 合并前的状态,执行 git rebase dev 来合并。
如图,因为 dev4 的变更提交早于 master4 的提交,所以 dev4 的提交就被合并到了 master4之前。也可以从可视化界面查看提交日志:
如图,rebase 合并在不会创建新的 commit 信息。
优点
git merge 不会对已有提交历史进行修改,保留了所有分支的提交历史,能够直观地看到每个功能分支是如何合并到主分支的。
而 rebase 因为没有合并提交,历史记录看起来就像所有开发都是在一条线上完成的,更容易追踪代码的演变。
缺点
git merge 因为合并会生成新的 commit 信息,如果有多个分支经常进行合并操作,提交历史可能会变得杂乱不堪,导致 git log 看起来非常复杂。
虽然 rebase 看起来就像一条线开发,但是会更改分支的提交记录。如果在公共分支上使用,会影响其他开发者的工作。
结语
不论是在分支全包含还是两个分支都有变更的情况下,rebase 就和 merge 的 fast-forward 模式一样,不会产生新的 commit 信息。
团队协作时,如果你希望保留所有开发者的开发记录,建议选择 git merge。个人开发时,如果喜欢线性整洁的开发记录,那么 git rebase 更合适。