浅谈git rebase命令:变基的作用

写在前面

既然文章的标题是浅谈,那自然是不做太详细的探究了,就举几个简单的例子,谈一谈变基、合并提交这两个操作的使用。至于为什么简简单单地内容都要记录下来,是因为笔者当初在搜索变基相关操作的时候,居然找不到一篇文章比较完整详细地讲清楚了“变基”这个过程涉及到的不同操作。笔者看到的要么就是写的太隐晦的,没点基础的读者估计绕不过来,还有一些就是抄来抄去的,连基本流程都没讲清楚的,便决定整理一下,于是有了这篇文章。

什么是变基

我们先来看看什么是变基,假设我们有下图所示的提交历史:
什么是变基(变基前)
这个时候我们会说,feature1分支是从develop分支上切出来的,具体一点也可以说,feature1分支是从develop分支的“develop第一次提交”这次提交上切出来的,如果此时对feature1分支基于develop分支进行变基,也就是先切到feature1分支,然后输入“git rebase develop”指令,提交历史会变成下面这个样子:
什么是变基(变基后)
此时,feature1分支的“切出点”从develop分支的“develop第一次提交”变成了“develop第二次提交”,变基其实就是改变这个“切出点”,或者说这个“切出点”其实就是被变的“基”。这个时候你会问了,这个东西有什么意义吗?我们接着来看变基的作用。

变基的作用

我们仍然以前面的例子为起点,假设有如下提交历史:
变基的作用(变基前)
此时将feature1分支合并到develop分支,就会得到如下提交历史:
变基的作用(不变基合并分支)
这个图里最显眼的地方无非就是feature1分支这段“绕出去”的提交历史。那么同样的起点,如果我先变基,你会看到前面那张变基后的提交历史图:
变基的作用(变基后)
此时如果将feature1分支合并到develop分支里,由于git的“fast-forward”合并,你最终会看到下图所示的提交历史:
变基的作用(变基后合并分支)
注意最新一次提交右侧分支名称的变化,最终的结果就是feature1分支那段“绕出去”的提交历史没了。这个时候你还是会继续问了:所以这有什么用吗?我想告诉你,作用就是:简洁美观。这里所谓的简洁是体现在多人开发时,多条分支“绕出去”的提交历史在develop分支上都被“拉”成一条直线,例如下面这样的提交历史:
变基的作用(两个功能分支)
这里将feature1分支、feature2分支当作是两个不同的人开发的,假设先合并feature1分支,再合并feature2分支,如果按照以往的合并方式,你会得到这样子的结果:
变基的作用(两个功能分支不变基合并)
但是如果先将feature1分支变基后合并进develop分支,再将feature2分支变基后合并进develop分支,你会得到这样子的结果:
变基的作用(两个功能分支变基后合并)
develop分支上的整个提交历史被拉成了一条直线,没有各个功能分支“绕出去”的痕迹。接下来要讨论的问题就是,这个简洁美观是必要的吗?

其实不是。仔细想想你会发现,变基之后的提交历史虽然好看,但是并不符合真实的开发历程,实际上当初开发feature1功能分支的人,就是从“develop第一次提交”上切出去的,但是最后的提交历史却并不是这个样子。类似的,当初开发feature2功能分支的人,是从“develop第二次提交”上切出去的,但是最后的提交历史却并不是这个样子。变基之后再提交的行为,在提供了简洁视觉的同时,丢失了提交历史的真实性,但是从另一个角度来说,反正最终的代码都是一样的,美观一点不好吗?这个就看你们项目组的选择了,是觉得美观一点比较重要,还是保留真实的提交历史比较重要。

变基是怎么一回事以及它的作用介绍完了,接下来要补充一点说明,你可能没有注意到,变基在改变“切出点”的同时,它其实也是另一个形式的分支合并操作,这里说的合并不是像前文那样变基之后合并两个分支,而是变基这个操作本身也是一次合并。我们回到起点从另一个角度重新看看:
什么是变基(变基前)
对于feature1分支而言,它是从“develop第一次提交”上切出来的,如果将它改成从“develop第二次提交”这里切出来,那它肯定要先把“develop第二次提交”的改动包含进来,然后叠加上feature1自己的改动,如果这两次提交修改了同一份文件的同一行内容,怎么办?其实在这个例子里面,将feature1分支变基的操作,和将develop分支合并到feature1分支里没什么区别,只是提交历史长相不同而已,有可能产生冲突,同样也要解决冲突。补充这一点是希望大家对变基有更进一步的理解,而不仅仅是记住“哦~切出点改变了耶,可以拉成直线了哇”。

变基的实际使用步骤

标题里说“实际使用步骤”,难道前面说的那些都不实际吗。其实前面说的知识点本身没有问题,只是举的例子还不够丰富,我们来看下图所示例子:
变基前(功能分支多次提交)
前面的例子里面功能分支都只有一次提交,如果有多次,情况会有点不同。根据feature1分支和develop分支具体的改动点不同,如果此时在feature1分支上对develop分支进行变基,你可能需要处理0~3次的冲突。最理想的情况是“f1第一次提交”的内容和“develop第二次提交”的内容完全一致,一次冲突都不需要处理,差不多就是一次fast-forward的分支合并效果。

如果“f1第一次提交”的内容和“develop第二次提交”的内容不一致,而且你在处理它们两的冲突时还两边的内容都取了一些,那你可能就要为“f1第二次提交”也处理一次冲突,以此类推,你可能需要为feature1分支上的每一次提交都处理一次冲突。那有没有办法让功能分支的多次提交,在变基的时候像只有一次提交那么方便呢?

有,git提供了“git rebase -i”指令来合并提交,注意它是合并提交,不是合并分支。如果我能够将feature1上的多次提交合并成一次,那变基的情况不就和只有一次提交一样了吗。所以你以为我们接下来要介绍如何合并提交吗,嘿嘿并不是,合并提交会产生一些问题,例如本来三次提交有三条描述信息,如果我合并成了一个,只能留下一条描述信息,那这个新的描述信息怎么输入呢?git通过vim编辑器来实现合并提交时和用户之间进行的交互,所以接下来我们不学习git了,先简单了解一下vim编辑器的操作,这里说的简单了解,意思就是只要满足本文的需求即可,不展开说。

vim编辑器简介

vim编辑器差不多是个类似记事本的东西,但它是纯键盘操作的,基本不响应鼠标事件,那么因此很多事情就需要通过键盘来输入指令,所以我们首先来了解一下vim编辑器的三个模式:
vim编辑器模式
当你使用vim编辑器打开一个文档的时候,就会进入命令模式,此时文档是不可编辑的,键盘按键不会被当成内容录入,而是被当成指令理解,而且多是单按键指令,此时按下i、a或者o就可以进入输入模式,输入模式下按下的按键会被当成内容输入到文档里面,也可以删改文档的内容,在输入模式下按下“ESC”键可以回到命令模式。在命令模式下按英文冒号(其实就是shift+冒号)就会进入底线命令模式,两个命令模式下都不可以编辑文档,主要区别在于命令模式支持的多是单按键指令,而底线命令模式允许你输入若干字符,敲击回车后才执行指令,也就是支持组合字符了,所以能使用的指令更多了。

对于合并提交,我们要做的操作大概就是从命令模式转到输入模式,修改文档内容,然后回到命令模式,再进入底线命令模式,保存退出,就可以了。vim就简单介绍到此,接下来看git的合并提交操作。

合并提交

我们还是用刚才的例子:
变基前(功能分支多次提交)
通过“git rebase -i”指令可以合并提交,这个指令有两个写法:

  1. “git rebase -i HEAD ~ n”
  2. “git rebase -i hash值”

第一个写法表示合并最近的n次提交,如果我想合并feature1分支的最近三次提交,那就输入“git rebase -i HEAD~3”,第二个写法表示将当前提交到指定提交之前的所有提交进行合并,这个“指定提交”就是通过hash值来指定,注意笔者这里用“指定提交之前”想要表达的意思是hash值所指定的提交是不被包含进来的。例如我想合并feature1的三次提交,指令里面需要写的是“develop第一次提交”的hash值,而不是“f1第一次提交”的hash值。
现在切到feature1分支,执行“git rebase -i HEAD~3”,你会看到这样的界面:
合并提交(选择指令)
此时已经处于vim编辑器的命令模式,这个界面是要我们选择如何处理这几次提交,顶部展示了将要被合并的三次提交,下面是对指令的解释,主要关注的就是pick和squash,pick表示使用这次提交,squash表示使用这次提交,但是融合到前面的提交去。所以我们的写法是第一行保持“pick”,后面几行均修改成“s”,表示将后面的提交都合并到第一次提交去,按下“i”进入输入模式,修改如下图所示:
合并提交(修改指令)
左下角的“-- INSERT --”表示vim编辑器处于输入模式,修改完后保存退出(输入“:wq”,键入回车),你会看到这样子的界面:
合并提交(修改描述信息)
需要说明一点,合并提交实际上是将几次提交的改动点合在一起,产生一次新的提交记录,原有的提交并不会被删除。既然产生了新的提交记录,自然要有描述信息,所以这个界面其实是让我们为这个新产生的提交输入描述信息。而且,git已经自动将被合并的几次提交的原有描述信息填上去了。我们一共合并了三次提交,所以这里展示了三次提交的描述信息,你可以在这里编辑描述信息。我们这里就不修改了,完后保存退出(输入“:wq”,键入回车),相当于把原有三次提交的描述信息复制在一起,作为新提交的描述信息,至此合并提交就完成了,此时输入git log,可以看到:
合并提交(完成)
你注意看这个提交的hash值,它和被合并的三次提交的hash值均不同,也证明了前文说的,这是一次新的提交,在图形界面你会看到这样子的内容:
合并提交(完成,图形界面)
对比命令行和图形界面,图形界面的左侧只显示了第一行的描述信息,实际上所有描述信息都保留了,可以在右侧看到。至此合并提交也介绍完了,接下来做最后一步:变基。

变基

既然多次提交已经被合并成了一次提交,接下来的事情就很简单了,输入“git rebase develop”指令,将feature1分支对develop分支进行变基。笔者这里由于有冲突,于是看到如下界面:
变基(处理冲突)
红色部分(是笔者自己圈出来的)告诉我们,处理完冲突之后,使用“git rebase --continue”继续,然后你会看到那个熟悉的vim编辑器界面:
变基(修改描述信息)
有个地方变基和合并提交类似,变基其实也不是真的把原有的提交“挪动”到新的“基”上,而是产生了一个新的提交,原有的提交并没有改变。所以你也可以修改新产生的提交的描述信息,这里我们也不做修改了,保存退出,最终提交历史变成下图所示:
变基(完成)
最后,你只需要切到develop分支,将feature1分支合并到develop分支里即可,这里我们就不演示了。

总结

本文通过几个简单的例子介绍了git里的变基是什么,以及它有什么作用。并借助一次完整的变基操作介绍了变基以及与此相关的合并提交、vim编辑器的简单操作。希望读者按照文章步骤可以顺利实现变基操作。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值