简析git 三种合并命令

1,455 阅读6分钟

适合初学者,大佬请略过。我们都知道代码合并有三种方式,分别是merge,rebase,cherry-pick。这三种git操作有各自的不同的体现,接下来我们按顺序来介绍这三种指令的用法及操作后的git分支的变化,希望对刚入门git指令的小伙伴有所帮助。

1. merge

  • git merge ${branchName}

merge操作一般用于分支之间的合并操作,commit树将变得不在“笔直”。下面将模拟一场merge操作。

假设从一个共有父节点创建两个分支,分别为master,bugFix,并有各自新的提交点c2, c3如下图: 当在分支master上执行git merge bugFix时,将产生新的提交点,commit信息提交树将变‘弯曲’,见下图: 可见,执行merge操作的代码合并,将清晰可见历史发生了什么,分支之间的关系是如何变化的,(如何看历史简单点git reflog,当然还有一些参数可以带在后面,这里不细挖。)砸们别跑偏了,接下来说说第二种合并操作rebase吧。

2.rebase

  • git rebase ${branchName}

说到rebase,我们先从英文单词的意思去理解下他的作用,英文词意有‘变基’之意,(hahhahhahha)那顾名思义是改变基点。那么他的特点就是:将使提交树看起来会更加简洁,他可能改变以往的的提交历史。一样砸们模拟下rebase分支合并的操作。

假设从一个共有父节点创建两个分支,分别为master,bugFix,并有各自新的提交点c2, c3如下图(还是那张图,嘿嘿):

砸们希望将bugFix和master分支合并,但又不想影响master分支,因为代码还没到上线那一刻,砸们不想污染master分支的代码啊,万一还有bug砸么办,又用rebase操作,来!首先想想到底是哪个基点想变化,以谁为准呢?这里以master为准,将bugFix的基点变化到master分支那里,此时如何操作呢?

  1. 切分支git checkout bugFix
  2. 启用rebase开始变基 git rebase master
  3. biu~操作完毕见下图哈

看到图我们就放心了,果然,bugFix的分支基点改变了,与master所在的树枝丫是一个岔哈。那么,在你检查完发现代码跟master的分支合并后,无任何bug(哇塞,太棒了!!),就应该更新master分支上的代码,加上bugFix上代码啦,此时如何操作呢?再上merge操作,基于上图如下操作:

  1. 切到master分支git checkout master
  2. 启用merge开始合并git merge bugFix
  3. 这个时候发生了什么,merge要合并的点就在前面,会不会产生像上面merge操作的‘弯曲’行为呢?不然要rebase干嘛用,看下图:

看到了吧,没有‘弯曲’,砸么回事儿,ooo, 对就是那个fast-forward吧!请看,经过一顿操作猛如虎,这条提交线好‘笔直’。你以为rebase就这点功夫吗?No,并没有!他还可以在自己的分支上rebase,那才是让你知道什么叫一顿操作猛如虎,但是,你可要明白,这是在改写历史,想清楚了,别改完后悔,这里没有药。

2.1 什么叫在自己分支上rebase

分析一个最常用到的场景:在自己的feature分支上,我们对一次需求进行着认真的开发,但是一日并不能完工,每天下班,代码都想存一存,放在缓存区好了,就会出现一次commit提交点,日复一日终于完成了整个需求,这天要与主分支合并了,一看好多提交点啊,放在主分支上也太多了吧,砸么办,来,上rebase!

git rebase -i HEAD~${n} 动态改变从当前提交点向后的n个提交点,如下图: 指令是git rebase -i HEAD~3自上而下的显示最近3次commit 信息,即最近一次提交在最下面,将三次合并成一次commit点,先操作再‘说’,将上图调成可编辑模式,不会(咦~别说自己四程序员)自己操作 control/command + i,将第一行pick改为reword,第二行到最后一行的pick都改为fixup,保存,将得到二页,可编辑合并以后的commit描述,想改就改,不改直接保存也可,最合合并成一条commit描述完毕。不熟练的小伙伴,实践多操作几次,以后你就是这条街最亮的仔了。 至于,那些个参数是什么意思,能读懂英文的小伙伴直接看上图Commands解释的非常,~呃,还可以,能大概知道,不行你就一个一个试试,反正熟能生巧,给你们个动手操作的机会,我稍微解释下。

参数简写含义
pickp用原commit描述,跟没操作似的
rewordr用commit描述,但可重新编辑,相当于默认执行--amend操作
edite用commit描述,会停下来问砸们需不需要操作--amend
squashs压缩提交,将几次提交合并成一次提交,且默认用s操作的commit描述
fixupflike squash,压缩呗,但放弃f操作的commit描述
execx没用过,不敢胡说
dropd删除commit,这个很危险(你看着办)
每次操作git命令时可注意下下面的操作解释,在执行rebase时等一些操作,有时候在对应步骤会出现提示操作git rebase --abort 放弃合并,小伙伴们要注意。

3.cherry-pick

cherry-pick也具有合并的作用,但是基于merge,rebase来说更为灵活,因为其将需要合并的分支的指定commit直接拽过来,实现合并,而不是将整个分支合并,优点: 将不必要的代码提交隔绝在外。 缺点:可能丢失有些代码,我遇到过但次数较少,为什么会这样,都是因为灵活性啊,看完面的模拟操作或许你就明白了。好吧,sao操作就是如此不严肃。接下来模拟下怎么用,提交树上有何反应。

假设从一个共有父节点创建两个分支,分别为master,sied,并有各自的分支上提交了些commit点如下图: 有个要求:将side分支上的c2,c4合并到master分支上,不要c3,砸么办,当然cherry-pick登场,在master分支上执行git checkout c2 c4,如下图: 这样c2,c4的‘影子’被拽到了master分支下,完成了此次合并。这里解释下之前说的缺点,为什么会掉一些代码,如果c4部分代码是基于c3代码修改,然而c2上又没有那部分代码,那么c4上对应代码的修改将不生效,这说明什么,说明cherry-pick只适合独立的各个提交点合并,不适合断章取义的sao操作。此处要小心了。

4.总结

  1. 合并代码的过程都有可能遇到冲突,需要手动解决
  2. 喜欢简洁的提交树可选择rebase合并
  3. 更注重提交历史清晰选择merge,但会增加新的合并提交点
  4. 灵活的cherry-pick小心使用非常方便

维护分支代码,和团队紧密合作love & peace

ps:推荐一个学习git命令的沙盒程序,记得给人家star哟。

文中若有不对,请指正,若有帮助,记得点赞哟。