Fork me on GitHub

Git rebase与merge的区别

Git场景

在基于Git版本控制的团队协作开发中,当同伴先于自己将新的提交push到远程分支上时,如果要想将自己新的提交push的远程分支,则需要先执行git pull来获取同伴的提交,如果有冲突则先处理完冲突,然后才能将自己的提交push到远程分支。这种情形是非常常见的。

然而执行git pull,在默认情况下,如果远程分支与本地分支的提交线图有分叉(即不是fast-forward,如上述这种情形),git会执行一次merge操作(即相当于执行了git pull --merge),而这会产生一次没有意义的提交记录。久而久之,项目的提交线图会非常混乱,其中会有很多由merge生成的无意义提交。

解决方案

为了避免这种情况的出现,在将提交push到远程分支之前,我们一般会执行如下命令:

1
$ git pull --rebase

通过上述命令,Git会采用rebase策略来代替默认的merge策略。从而避免生成无意义的提交。

分析对比

这时候,我们可能就会想:既然merge操作会生成无意义的提交,那它是不是没有什么价值了呢?是不是任何场景下都应该使用rebase操作?

所以,我们对rebase和merge进行分析和对比。了解清楚了两者的区别,我们才能更好地运用这两个策略。

场景设想

假设在执行pull之前的提交线图如下所示:

Merge操作

如果执行git pull(git默认会执行git pull --merge),提交线图会变成如下所示:

分析
提交线图中多出了一个没有必要的提交H

Rebase操作

如果执行git pull --rebase,提交线图会变成如下所示:

分析
提交线图中,本地的新提交FG变成了两个新的提交F'G',拼接在了C后面,多余的分叉也删除了。提交线变得非常清晰。

小结

从上述对比可以看出,rebase操作会将本分支的新提交删除并生成新的提交。所以rebase操作比较适用于将一些零碎的提交进行合并清理。比如:在push之前进行整理。

那么merge操作意义何在呢?

merge操作与rebase操作相反,它可以保留了提交线图的分叉,并生成一个新的提交。这种场景适合用于大的分支合并。这样,我们可以在提交线图中看到项目开发迭代过程中经历过哪些feature分支等等。

注意
如果执行merge操作之前,提交线图是分叉的(即不是fast-forward,如场景设想的情形),执行git merge操作,是会达保留分支的目的。

但是执行merge操作之前,提交线图不是分叉的(即是fast-forward,如下上图所示),此时执行git merge操作的效果如下下图所示,分支是不会保留的。

fast-forward情况下进行合并,我们需要执行如下命令来保留分支。执行后的提交线图如下所示。

1
$ git merge --no-ff

(完)

欣赏此文?求鼓励,求支持!