Git命令 rebase vs merge

 

今天因为一些机缘巧合了解了一下 git的合并命令,rebase和merge。由于公司在这方面没有什么规定,自己平时一直都是用的merge命令来合并代码。但是再往回想想,上一个领导就推崇使用rebase来合并代码,原因就是因为merge合并,会使log看起来非常的杂乱,而使用rebase来合并则会让log看上去非常漂亮有秩序。

在上一家单位时,当时也没有深究,今天索性就稍微深入了解一下这两种合并方式的区别。先贴一下我观摩的链接,https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA

首先总结一下,其实两种方式都可以达到一样的目的,即合并代码。merge更加无脑简单,而rebase更加强大,同样也带来了一定的问题。

首先先说一下merge操作

Git命令 rebase vs merge

如图所示,C4(即experiment分支)是基于master分支的C2拉出的,在C2的基础上提交了C4。

C3则是在C2的基础上提交的

现在在master分支上对experiment分支进行merge操作,即发生了上图的结果。将两个分支最新快照(C3,C4)以及二者最近的祖先C2进行三方合并,然后提交了C5。

 

举一个例子:

现在有两个人负责一个项目,之前稳定版本就是在C2这个节点。现在突然发现了一个BUG,让A同事去修复这个BUG,A则基于C2节点拉出了自己的分支(experiment)修改了BUG,提交之后形成了C4。

项目不停还有新的需求进来,然后B同事基于C2开发了C3功能。

现在需要发版了,要将之前修复BUG的代码合并到master分支。领导在master分支上合并了experiment分支,最后形成了C5。

 

再来说说rebase操作,还是上面的操作,要将A同事C4合并到master分支上,使用rebase的结果是

Git命令 rebase vs merge

rebase用中文的意思是变基,顾名思义,就是将之前的基础变掉,换成新的基础。

先贴一下命令

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

之前C4的基础是C2,我们执行了变基命令后,C4的基础变成C3了。看上去就好像C4是就是基于C3拉出来的一样。git log看上去确实美观很多。

然后,切回master分支,我们再合并(merge)一次experiment分支

$ git checkout master
$ git merge experiment

 Git命令 rebase vs merge

这个时候,两个分支的代码就一模一样了。

这两种合并方式最终指向的快照结果(代码)都是一样的,区别就在于git log上,rebase更加美观。

它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。(大概意思就是 先把experiment分支相对于C2的多次提交先放到一边,把当前experiment分支指向C3,然后再把之前临时放到一边的文件应用到C3上

文中还写到 rebase的另外一种用法。在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行应用。


下面再说说rebase的风险点

使用rebase有一条准则:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。(你提交的东西,别人还要基于你提交的东西进行修改的话,那就不要用rebase)

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。这句话很重要

下面图中 master表示本地仓库代码、teamone/master表示远程仓库代码

Git命令 rebase vs merge

一步步来说吧

A图 你从主线拉了代码,最新到C1。

B图 你commit了C2,C3到主线

Git命令 rebase vs merge

A图 另一个同事提交了C4,还合并了一个C5,形成了C6的提交(两个分支最新快照(C4,C5)以及二者最近的祖先C1进行三方合并,然后提交了C6),现在远程仓库最新节点为C6

B图 你拉取(merge)了那个同事提交的代码形成了B图,由C3,C6合并形成了C7(两个分支最新快照(C3,C6)以及二者最近的祖先C1进行三方合并,然后提交了C7)

Git命令 rebase vs merge

A图 这时,这个同事把之前的合并操作回滚,用变基。继而又用 git push --force 命令覆盖了服务器上的提交历史

B图 你拉取了(文中的意思应该是 git fetch)最新的代码,发现又多出一个C4'的提交

Git命令 rebase vs merge

这时,如果你使用git pull,那么你就会把C7和C4'合并了形成C8提交。git pull = (git fetch 和 git merge )。

这时候就很尬尴了,C4出现了2次。

然后,这时候你再继续提交的话,实际上是你把那些已经被变基抛弃的提交又找了回来。很明显那个人不想在提交历史中看到 C4 和 C6,因为之前就是他把这两个提交通过变基丢弃的

解决办法就不写了,自己看原文吧。所以在实际应用中,不要再公共分支上用rebase。以免发生这种头疼的事情

 

上一篇:Git--IDEA界面操作


下一篇:最新git从入门到项目实战教程2019年8月新课