从git merge 和 git rebase想到……

时间:2021-08-09 20:34:40

  起因

  前两天和项目组的成员分享了git相关知识,因为我发现大家再运行git pull时没有加后面的参数 --rebase。

  也就是说,如果你运行git pull,那么git会帮你做两件事情,首先拿到远程最新的代码,然后运行 git merge。

  那么如果是git pull --rebase呢?也是会拿到最新代码,然后运行git rebase。

  接下来的问题就是git merge 和git rebase的区别了。简单来说,git merge和git rebase从最终效果来看没有任何区别,都是将不同分支的代码融合在一起,但是生成的代码树就稍微有些不同。(具体请猛击这里

  那么假设下面两个代码树,你愿意维护或者继续再那一个上面进行工作呢?

从git merge 和 git rebase想到……                                        从git merge 和 git rebase想到…… 

  (1)git merge                                   (2) git rebase

  如果是我,我会选择第二个,因为它整体是一个线性开发过程,看起来一目了然。而第一种显然被很多分支搞的很乱(你能告诉我图1中那个颜色的分支是master分支么?)

 

  分析

  好吧,大家显然没有被上面的理由说服,我们又开始了很多对话。大体的意思是使用git merge有以下两个好处

  1. 和git rebase的结果没有区别 -_-

  2. 小组内每天下午都要code review,大家发现在review的时候,大家的提交不是按时间先后排序的,也就是说提交顺序可能如下A的22号提交,A的21号提交,B的22提交,B的21提交。用git merge就不会出现,你一定会问这和git merge有什么关系?

  答案是有关系的,看个例子把。  

  我有两个相同的branch,一个是master,一个是test。我现在test上面提交 1: first commit on test,然后切换到master上面提交2: first commit on master,然后再切换到test上面,进行提交3:second commit on test。接下来,我们就要进行合并了。

  生成代码树如下图:  

从git merge 和 git rebase想到……

  如果你使用git merge,合并的结果master分支的log就是:

commit e0db7b4335aa5a18a5d0777578b3b313b038cd7e
Merge: e737698 6ca7468
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:22:00 2011 +0800

Merge branch 'test'

commit 6ca7468ab141dff03ec11fa4775ac7b968b18c7d
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:17:37 2011 +0800

3 : second commit on test

commit e737698564c61f1472b4cb62974cf66670e2991b
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:16:51 2011 +0800

2: first commit on master

commit 59820371d4df099310423736ca3fc5e9d9e30f95
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:16:28 2011 +0800

1 : first commit on test branch

  可以看到log的顺序是我们想要的,是按照提交时间来排序的,因为git merge会将两个分支的合并结果放在最后。

  但是如果你使用git rebase,那么你会得到:

commit 828e9edde44ed2a830913a3bfa4008cfc3679faa
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:17:37 2011 +0800

3 : second commit on test

commit 0567e43b42278839ae10231b66a6ff43e70255f9
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:16:28 2011 +0800

1 : first commit on test branch

commit e737698564c61f1472b4cb62974cf66670e2991b
Author: Mao Chao <chaomao@thoughtworks.com>
Date: Tue Dec 6 21:16:51 2011 +0800

2: first commit on master 

  表面来看,git rebase没有按时间排列全部提交,因为rebase会把当前分支的提交放在要合并分支的后面,所以test分支上面的1和3提交排在master的2提交的后面。这样显得很乱,相反git merge却给你一个按时间排列的代码树。你也许想说:我想要全部的提交都按照时间来排序而使用git merge。

  这是一个大大的借口!!!

  我们需要的是频繁合并!!!

  git rebase忠实的保留你合并的顺序,假如你没有频繁提交、合并分支,那么你的log就会忠实的反应出来,而不是像git merge一样掩盖问题。问问自己,如果我能做到完成test分支的1提交时就合并到master上面,那么2->1->3的情况还会出现么?

  所以,请勇敢地用git rebase来检验你的团队是否频繁提交吧。

 

  疑惑

  其实,我一直难以回答的团队内部的一些问题:

  我这么做能得到什么好处?

  我不这么做也能达到效果呀~~   

  (于是,我就得绞尽脑汁的回答git rebase vs git merge这种问题,有时候也很享受这种过程,想想以后如果出去做咨询,面对的是客户更加严厉的质疑,回答这种问题肯定是家常便饭了,幸运的是,我真的想出一种场景,使用git rebase生成出来的一条线能更加方便的确定每次提交后的程序状态。)

  在这里,我不想再继续纠结这些问题,我能否问你一些问题:

  为什么你要加入Thoughtworks?

  为什么你要写干净的代码?

  为什么你不能频繁提交?

  为什么你不能追求卓越?

  

  如果下次还有人问我类似的问题,我想我已经有答案了,那就是我们要追求卓越