请注意,git(以及几乎所有其他版本控制系统)调用此变基onto, not into.
你确实可以做这种变基。然而,重要的是要知道,当你对某些提交进行 rebase 时,git 实际上copies他们到new承诺。这会影响共享代码的每个人,if他们已经拥有了old承诺。
图片
假设您现在可以这样绘制:
...--N--O--P--Q--R <-- master
\ \
\ J--K <-- A
\
E--F--G <-- B
这里分行A
提交点K
, 分支B
提交点G
,和分支master
提交点R
(现在每个提交都有这些单字母代码,以便我们可以更轻松地识别它;实际上,它们的名称是 SHA-1 哈希值,例如bfcd84f529b...
)。提交N
通过R
因此在master
(以及隐藏在左侧的所有提交N
);提交N
, O
, P
, J
, and K
(以及所有剩下的提交N
和以前一样)在分支上A
;并承诺N
, E
, F
, and G
(以及所有剩下的提交N
一如既往)在分支机构B
.
合并基地
Commit N
is the merge base of branches B
and master
, and commit P
is the merge base of branches A
and master
. The merge base is simply1 the commit after which the branches diverge, which becomes easy to see if you draw the graph as we just did. This matters for your git rebase
because the default method git uses is to find this merge base commit, and copy commits that are after that point. (And, this means that before you do a rebase, it may be a good idea for you to draw the graph, so that you can see what you will be doing.)
复制提交
要自己复制单个提交,请使用以下命令git cherry-pick
。您现在不需要这样做——rebase 会为您做这件事——但最好了解它是如何工作的,所以让我们简单介绍一下。
在 git 中,每次提交都是一个完全独立的快照。例如,考虑提交F
在树枝上B
。犯罪F
包含截至您提交时与您的项目关联的完整源代码树F
。提交也是如此E
and G
。要是我们compare commit E
与提交F
, 我们会看到发生了什么变化在“提交树”之间E
”和“提交树F
”。同样,如果我们比较F
vs G
,我们会发现从F
to G
.
将提交转换为一组更改——称为变更集——让我们能够copy一次提交。例如,假设我们看到发生了什么N
to E
。然后进一步假设我们检查提交K
和做同样的改变,然后将其提交到一个新的临时分支上:
...--N--O--P--Q--R <-- master
\ \
\ J--K <-- A
\ \
\ E' <-- temp branch
\
E--F--G <-- B
我调用了新的提交E'
,而不是给它一个新的单个字母,因为它是copy提交的E
。这不完全是same作为提交E
当然。一方面,它有一个不同的父级(它有提交K
作为其父级);它可能还有很多其他区别E
:特别是提交中发生的任何事情O
, P
, J
, and K
,因为我们现在已经应用了“来自N
to E
到“里面有什么”K
".
Rebase只是重复的副本
git rebase
作品作者:
- 识别要复制的提交;
- 使用临时分支复制它们;和
- 重新指向原来的分支。
If you git checkout B
进而git rebase A
,步骤 1 中确定的提交是在合并基础之后的提交B
and A
,直到树枝的尖端B
. The A
and B
这是因为您当前的分支是B
你说git rebase A
.
练习:查看图表并确定以下的合并基础B
and A
。可能有点难以发现,但是如果我们像这样重新绘制图表呢?
Q--R <-- master
/
...--N--O--P--J--K <-- A
\
E--F--G <-- B
(这张图从拓扑上来说,一模一样正如我们绘制的原始图表,但现在非常明显的是,提交N
是合并基础。)
简而言之,这些都是提交E
, F
, and G
。因此,rebase 继续执行步骤 2 并复制这三个提交,将副本放置在分支尖端之后(“到”)A
(因为你说git rebase A
).
因此,在变基过程的这一点上,我们现在有:
Q--R <-- master
/
...--N--O--P--J--K <-- A
\ \
\ E'-F'-G' <-- temp
\
E--F--G <-- B
rebase 现在只剩下最后一件事了,就是重新指向当前分支B
,到刚刚复制的最后一次提交。这很简单:
Q--R <-- master
/
...--N--O--P--J--K <-- A
\ \
\ E'-F'-G' <-- B
\
E--F--G [abandoned]
原来的承诺,E
通过G
,此时大部分都消失了(它们仍然通过reflog对于分支机构B
但除非你专门看那里,否则你不会再看到它们)。新的副本,E'
通过G'
,已添加到刚刚经过分支的尖端A
.
为什么这一切都很重要
所有这些复制和洗牌都发生在你的存储库, and not在您的存储库的其他人的副本中。这意味着任何同事或集中服务器还没有这些副本。如果你git push
将副本发送到集中式服务器,该服务器将获得副本 - 但如果该服务器有原始的、现已废弃的、提交的,并且如果该服务器调用该“分支”B
”,您将必须强制推送到服务器。
执行此强制推送将使服务器丢弃原始提交的副本,并将复制的提交放在适当的位置并将其称为“分支”B
“。 这是真实的even if,在服务器上,有一个提交H
随后提交G
, 有分支B
指向提交H
. 换句话说,这可能会“丢失”服务器的提交。这是第一个问题:您必须与使用服务器的其他人协调,这样您就不会丢失提交。
此外,在进行强制推送后,和/或如果您的同事正在共享您的存储库(通过从中获取/拉取),您的同事可能需要调整their存储库来解释复制提交和移动分支标签。对他们来说,这是一个上游变基 and 他们必须从中恢复过来。这是第二个问题:您必须与使用该分支的其他人进行协调,以便他们知道如何从上游变基中恢复。
简而言之,确保所有合作开发人员都同意这一点。
如果您有其他人与您一起工作,并且他们共享您将重新建立基础的分支,只需确保他们都知道这一点即可。如果您要变基的这些提交是not已发布(如果它们纯粹是您自己的存储库私有的),那么这种协调根本不需要任何努力,因为没有其他人可以通知,因此没有人可以反对它。
合并,也许再次变基
Soon A
将被合并到master
(前B
), 但是不是现在。然后,当我合并时B
,它会破坏引用吗A
重新基于它?
同样,回答这些问题的方法是从绘制提交图开始。让我们使用新的、重新基础的绘图,然后添加合并的合并提交B
into master
。由于我们想要显示合并,因此我们需要再次重新绘制图形,以便更容易连接行:
...--N--O--P-Q-R <-- master
\
J--K <-- A
\
E'-F'-G' <-- B
现在我们要跑git checkout master
and git merge A
进行新的合并提交M
:
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' <-- B
我们不需要改变任何东西B
在这里,我们可以像往常一样继续开发它。但是,如果我们want如果我们所有的共同开发者都同意的话,我们现在可以重新建立基础B
再次,这次到master
.
If we git checkout B; git rebase master
, the rebase
将像往常一样,首先找到之间的合并基础B
and master
。合并基础是什么?查看图表并找出其中的点master
and B
参军。这绝对不是新的合并提交M
,但它不是N
也不再有。
分支上的提交B
are N
, O
, P
, J
, K
, E'
, F'
, and G'
(以及我们看不到的任何提交都位于N
)。这部分很简单。棘手的部分是分支上的提交master
。这些都是N
, O
, P
, Q
, R
, and M
, but also J
and K
。这是因为这两个提交可以通过以下提交来实现M
's second parent.
因此,合并基础(定义为两个分支上“最接近”的提交)实际上是提交K
。这正是我们想要的!变基B
onto master
, we wantgit 复制E'
, F'
, and G'
。新副本E''
, F''
, and G''
将会追随M
,我们会得到这个:
E''-F''-G'' <-- B
/
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' [abandoned]
这里真正的教训是绘制图表因为它会帮助您弄清楚发生了什么。
1At least, it's simple when there is a single such point. In more complex graphs, there can be more than one merge base. Rebasing with complex graphs requires a lot more than I can write in this particular SO posting, though.