全网最通俗易懂的讲解: git rebase和git merge的原理和区别 [ ⭐️建议收藏]

10,959 阅读4分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

前言

我们在上篇文章你想知道的所有Git分支命令都在这中提到了git merge 命令,可以将其中一个分支的代码合并到另一个分支中,其实还有另一种方法,通过 git rebase命令也可以实现,但是两者的实现方式还是有很大差异的,网上有很多文章都对其差异有讲解,但大多数说的都很模糊不够清晰,看的也是一知半解,如果一篇文章对读者而言做不到通熟易懂那就是对读者的不负责,本篇文章将使用最通熟易懂的语言让你彻底搞懂两者的差异。

先说结论:

  • merge 是一个合并操作,会将两个分支的修改合并在一起,默认操作的情况下会提交合并中修改的内容
  • merge 的提交历史记录了实际发生过什么,关注点在真实的提交历史上面
  • rebase 并没有进行合并操作,只是提取了当前分支的修改,将其复制在了目标分支的最新提交后面
  • rebase 操作会丢弃当前分支已提交的 commit,故不要在已经 push 到远程,和其他人正在协作开发的分支上执行 rebase 操作
  • merge 与 rebase 都是很好的分支合并命令,没有好坏之分,使用哪一个应由团队的实际开发需求及场景决定

image-20211104214737342

先来说说 git merge的实现方式

如上图所示,我们有两个分支,master 分支和 test 分支,test 分支是基于 master 分支在B处的提交节点创建的,在创建后 master 分支又经过迭代提交了两次,从C到D节点,test 分支也基于B往前继续更新了两次,到了F节点。两者从B开始就走向了分叉。

这时如果我们想将 test 分支合并到 master 分支,通过 merge 是如何工作的呢?

//将分支切换到master分支
git checkout master
​
//把test分支合并到master分支
git merge test

image-20211104215627579

从图中可以看到,这里生成了一个新的提交G,是怎么生成的呢? merge 命令 它会把两个分支的最新快照(F、ED、C)以及二者最近的共同祖先(B)进行三方合并,合并的结果是生成一个新的快照G(并提交)。

git rebase实现方式

//将分支切换到master分支
git checkout master
​
//把test分支合并到master分支
git rebase test

从图就可以看出和 merge 命令不同

这里有个名词定义我们先简单说明一下

  • test:基分支、目标分支
  • master: 待变基分支,当前分支

官方解释: 当执行 rebase 操作时,git 会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。

这句话听起来可能绕绕的,不用怕,听小蛋给你好好翻译翻译:

我们结合具体例子来说明,当我们在master (待变基分支)上执行git rebase test(基分支)时,git就会从两者的共同祖先B开始,提取 master 分支上的修改,也就是 C,D 两个 commit ,提取到之后 git 会先保存起来,然后将master 分支指向 test 分支最新提交的节点,也就是F节点,然后把提取到的 C,D 接到F后面,在这个过程当中,会删除原来的C,D commit 记录,生成新的C‘,D',虽然C',D'和原来的C,Dcoommit的内容是一样的,但是 commit id 是不同的。

rebase 操作如果用一句话进行解释就是改变基底。master 分支原来的基底是A,现在变成了以 test 分支最新的提交F做为新的基底了。

总结

merge 和 rebase 这两者哪种操作更好,这是取决于不同的场景的。

当我们拉取公共分支最新代码的时候建议使用rebase,也就是git pull -rgit pull --rebase,但有个缺点就是 rebase 以后我就不知道我的当前分支最早是从哪个分支拉出来的了,因为基底变了嘛。(如果使用 merge ,多出无意义的一条提交记录)。

往公共分支上合代码的时候,使用 merge 。(如果使用 rebase ,那么其他开发人员想看主分支的历史,就不是原来的历史了,历史已经被你篡改了),例如主分支是 master 分支,小蛋我有一个 egg 分支,我在 egg 分支上写了很多垃圾代码,然后这时候我把 egg 分支通过 rebase 命令合并到 master 分支,那对于 master 分支来说,它之前到提交历史就没了,别的同事突然想看 master 分支以前的提交历史,其实就看不到了,发现只能看到我 egg 的提交历史,估计同事会把我的 egg 捏碎的,这种傻事可不要干哟。