git

git系列3/3:掌握rebase

Posted by jygao on May 10, 2020

pull rebase 的优雅

这篇是我之前这篇博文中解释rebase是到底是什么和它的黄金法则。正如很多人指出的,大部分Anna的麻烦都可以避免假如她使用pull rebase。在之前我不大想讨论这个,为了让我的文章短一点,但是现在是时候了。

让我们假设Bob在一条落后于远程的分支上工作,他的历史看起来像这样子的:

然后Bob现在决定这是他pull的一个好的时候,你可能猜到这里会有一些问题。因为Bob是落后于GitHub上的远程分支的,git 将会询问他并做一个合并(merge),结果会是这样子的:

这个解决方法完全没有问题,并且可以完美的工作,然而你可能还想知道有没有其他的方法去解决这个问题的。有的,其中之一便是 pull - rebase

当你做一次pull -rebase的时候,git会计算出哪些commit是你的本地分支上独有的,哪些是在远程分支上的。它把远程仓库上的那些和你本地仓库的最近一次同步远程的commit合并。然后在在那条分支的顶端rebase你的“本地“”的commit 。这听起来也许很复杂但是实际上并不:


第一步:git 只关心那些同时在你的本地分支和远程分支上的commits

你可以直观的看到,它是远程分支的一个简单的副本:

第二步:git rebase 本地commits

如果你记得,在rebase过程中,git把commits一个一个重新生成(reapplay)了一遍,这就是现在所发生的。Git会在master分支的顶部重新生成一个E节点,然后到F节点。注意到这个例子是,一条分支基于它本身rebase。哼,ok,但是这又是为了啥?我还是喜欢merge。

好吧,对于我,用merge最大的问题是:它经常污染了历史记录,即使毫无必要这么做的。pull -rebase,在我看来,更加优雅。我会更近一步说明为什么当你想要pull最新的变更到你的分支时,你应该总是选择用pull -rebase。但是小心点,因为rebase是一个一个commit重新生成的,如果你rebase20个commmits,你可能不得不解决20个冲突,而且你得一个个的解决它。

根据经验,我猜我们可以这么说:1.大的变更,很长时间的变更,用merget 2.小变更,最新的更改,用:pull-rebase

rebase — onto的威力

假设你得历史看起来是这样的:

fig 1

fig 1

f

假如你想rebase feature 2 分支,基于master。如果你用了一般rebase master,你会得到如下:

fig 2

fig 2


如果你看回fig1,你可能觉得有点违反直觉,commit D 同时属于分支 feature1 和feature2。因此,如果你基于master分支rebase feature2分支,commit D会和F跟G一样,会被重新生成在master分支的顶端。那现在如果我是要如下的结果呢:

[fig](http://bit.ly/1YuTE8K) 3
fig 3

f

这时候就是git rebase --onto 进入游戏的所在了。首先,让我们从读官方文档开始:

我们特别关注下 --onto选项:

像往常一样,我们试着翻译一下这些隐秘的句子。这个参数是你rebase的目的地,一个commit或者分支名,(你想基于它rebase的你的分支),在我们这例子这里,它是master。

你也可以使用第二个参数(一个非常糟糕的名字),第二个参数可以看作是你要作为基准的第一个提交。

我们看得更清楚些,如果我们看下图:

所以,这里我们所需要做的是:在feature2上,执行:
git rebase — onto master feature1

这样我们就能直接得到我们看到fig3那样的结果了。