我可以安全地将一个分支变基到另一个分支然后掌握吗?
Can I safely rebase one branch into other and then to master?
我必须开发分支,我根据分支 A
.
中的代码找到了分支 B
我想将 A
变基为 B
,这样我就可以继续开发 B
。
很快 A
将合并到 master
(在 B
之前),但不是现在。然后,当我合并 B
时,它是否会破坏引用,使 A
重新基于它?
然后我可以在 master
上对 B
进行变基,一切都会好起来的吗?还是我需要执行任何特殊步骤?
请注意 git(以及几乎所有其他版本控制系统)将此变基称为 onto,而不是 in到.
你确实可以做这种rebase。然而,重要的是要知道当你变基一些提交时,git 实际上 复制 它们到 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
和 K
(以及 N
之前的所有提交)都在分支 A
;并提交 N
、E
、F
和 G
(以及 N
左侧的所有提交一如既往)在分支 B
上。
合并基地
提交N
是分支B
和master
的合并基础,提交P
是合并基础分支 A
和 master
。合并基础只是1 分支分叉之后的提交,如果你像我们刚才那样画图就很容易看出。这对您的 git rebase
很重要,因为 git 使用的默认方法是查找此合并基础提交,并且 copy 提交 after那个点。 (而且,这意味着在你做一个变基之前,你最好画一下图,这样你就可以看到你将要做什么。)
复制提交
要自己复制单个提交,请使用命令 git cherry-pick
。你现在不需要这样做——rebase 会为你做——但了解它是如何工作的是个好主意,所以让我们简要介绍一下。
在git中,每次提交都是一个完全独立的快照。例如,考虑在分支 B
上提交 F
。提交 F
包含与您的项目关联的完整源代码树,截至您提交 F
时。提交 E
和 G
也是如此。如果我们比较提交E
与提交F
,我们将看到在"the tree for commit E
"和[之间发生了什么变化 =311=]。同样,如果我们比较 F
和 G
,我们会发现从 F
到 G
发生了什么变化。
将一个提交转换为一组更改——称为变更集——允许我们复制一个提交。例如,假设我们看到从 N
到 E
发生了什么。然后进一步假设我们检出提交 K
并进行 相同的更改 ,然后将其提交到一个新的临时分支:
...--N--O--P--Q--R <-- master
\ \
\ J--K <-- A
\ \
\ E' <-- temp branch
\
E--F--G <-- B
我将新提交称为 E'
,而不是给它一个新的单个字母,因为它是提交 E
的 副本。当然,它与提交 E
不完全相同。一方面,它有不同的父级(它有提交 K
作为它的父级);它可能与 E
有许多其他差异:特别是在提交 O
、P
、J
和 K
中发生的任何事情,因为我们已经现在应用 "the changes from N
to E
onto "K
中的内容。
rebase只是重复拷贝
git rebase
作品作者:
- 识别要复制的提交;
- 正在使用临时分支复制它们;和
- 重新指向原来的分支。
如果你 git checkout B
然后 git rebase A
,在步骤 1 中识别的提交是那些在 B
和 A
之间的合并基础之后的提交,直到分支B
。这里的 A
和 B
是因为你当前的分支是 B
而你说 git rebase A
.
练习:看图并识别 B
和 A
的合并基础。可能有点难发现,但是如果我们像这样重新绘制图形呢?
Q--R <-- master
/
...--N--O--P--J--K <-- A
\
E--F--G <-- B
(这张图从拓扑上来说,和我们原来画的图完全一样,但是现在超明显commit N
是merge base .)
简而言之,这些是提交 E
、F
和 G
。所以 rebase 继续第 2 步并复制这三个提交,将副本放在 ("onto") 分支的尖端之后 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
的末端。
为什么这一切都很重要
所有这些复制和改组都发生在您的存储库中,并且不会发生在您存储库的任何其他人的副本中。这意味着任何同事或中央服务器还没有这些副本。如果您 git push
将副本发送到中央服务器,服务器将获得副本——但是如果服务器有原始的、现在被遗弃的提交,并且如果服务器调用它 "branch B
",您将必须强制推送到服务器。
执行此强制推送将使服务器丢弃其原始提交的副本,并放置复制的提交并调用它们 "branch B
"。这是真的即使,在服务器上,在提交G
之后有一个提交H
,分支B
指向提交H
。 换句话说,这可以 "lose" 从服务器提交。 这是第一个问题:你必须与使用服务器的其他人协调,这样你就不会丢失提交。
此外,在执行强制推送后,and/or 如果您的同事正在共享您的存储库(通过 fetching/pulling 来自它),您的同事可能需要调整 他们的 存储库来说明复制提交和移动分支标签。对他们来说,这是一个上游变基,他们必须从中恢复。这是第二个问题:您必须与使用该分支的其他人协调,以便他们知道从上游 rebase 中恢复。
简而言之,请确保您的所有合作开发人员都同意这一点。
如果您有其他人与您一起工作,并且他们共享您将变基的分支,请确保他们都知道。如果您将变基的这些提交 未 发布——如果它们完全是您自己的存储库私有的——那么这种协调根本不需要任何努力,因为没有其他人可以通知,所以没有人可以反对。
正在合并,可能会再次变基
Soon A
will be merged to master
(before B
), but not now. Then, when I merge B
, will it break the reference from having A
rebased on it?
同样,回答这些问题的方法是从绘制提交图开始。让我们使用新的、重新定位的绘图,然后添加将 B
合并到 master
中的合并提交。由于我们要显示合并,我们需要再次重新绘制图形,以便更容易连接行:
...--N--O--P-Q-R <-- master
\
J--K <-- A
\
E'-F'-G' <-- B
现在我们将 运行 git checkout master
和 git merge A
进行新的合并提交 M
:
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' <-- B
我们不必在此处更改 B
中的任何内容,我们可以像往常一样继续开发它。但是,如果我们想要——并且如果我们所有的合作开发者都同意——我们现在可以再次变基B
,这次是master
。
如果我们 git checkout B; git rebase master
,rebase
将像往常一样从找到 B
和 master
之间的合并基开始。什么是合并基础?查看图表并找到 master
和 B
连接的点。它绝对不是新的合并提交 M
,但也不再是 N
。
分支 B
上的提交是 N
、O
、P
、J
、K
、E'
、F'
和 G'
(以及 N
左侧我们看不到的任何提交)。这部分很简单。棘手的部分是分支 master
上的提交。这些是 N
、O
、P
、Q
、R
和 M
,但 也 J
和 K
。这是因为这两个提交可以通过跟随提交 M
的 second parent.
来实现
因此,合并基础(定义为两个分支上的 "closest" 提交)实际上是提交 K
。这正是我们想要的!要将 B
变基到 master
,我们 想要 git 复制 E'
、F'
和 G'
.新副本 E''
、F''
和 G''
将在 M
之后,我们将得到:
E''-F''-G'' <-- B
/
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' [abandoned]
这里真正的教训是绘制图形,因为它会帮助您弄清楚发生了什么。
1至少只有一个这样的点就简单了。在更复杂的图中,可以有多个合并基础。不过,使用复杂的图形进行变基需要的内容比我在这个特定的 SO 帖子中写的要多得多。
我必须开发分支,我根据分支 A
.
B
我想将 A
变基为 B
,这样我就可以继续开发 B
。
很快 A
将合并到 master
(在 B
之前),但不是现在。然后,当我合并 B
时,它是否会破坏引用,使 A
重新基于它?
然后我可以在 master
上对 B
进行变基,一切都会好起来的吗?还是我需要执行任何特殊步骤?
请注意 git(以及几乎所有其他版本控制系统)将此变基称为 onto,而不是 in到.
你确实可以做这种rebase。然而,重要的是要知道当你变基一些提交时,git 实际上 复制 它们到 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
和 K
(以及 N
之前的所有提交)都在分支 A
;并提交 N
、E
、F
和 G
(以及 N
左侧的所有提交一如既往)在分支 B
上。
合并基地
提交N
是分支B
和master
的合并基础,提交P
是合并基础分支 A
和 master
。合并基础只是1 分支分叉之后的提交,如果你像我们刚才那样画图就很容易看出。这对您的 git rebase
很重要,因为 git 使用的默认方法是查找此合并基础提交,并且 copy 提交 after那个点。 (而且,这意味着在你做一个变基之前,你最好画一下图,这样你就可以看到你将要做什么。)
复制提交
要自己复制单个提交,请使用命令 git cherry-pick
。你现在不需要这样做——rebase 会为你做——但了解它是如何工作的是个好主意,所以让我们简要介绍一下。
在git中,每次提交都是一个完全独立的快照。例如,考虑在分支 B
上提交 F
。提交 F
包含与您的项目关联的完整源代码树,截至您提交 F
时。提交 E
和 G
也是如此。如果我们比较提交E
与提交F
,我们将看到在"the tree for commit E
"和[之间发生了什么变化 =311=]。同样,如果我们比较 F
和 G
,我们会发现从 F
到 G
发生了什么变化。
将一个提交转换为一组更改——称为变更集——允许我们复制一个提交。例如,假设我们看到从 N
到 E
发生了什么。然后进一步假设我们检出提交 K
并进行 相同的更改 ,然后将其提交到一个新的临时分支:
...--N--O--P--Q--R <-- master
\ \
\ J--K <-- A
\ \
\ E' <-- temp branch
\
E--F--G <-- B
我将新提交称为 E'
,而不是给它一个新的单个字母,因为它是提交 E
的 副本。当然,它与提交 E
不完全相同。一方面,它有不同的父级(它有提交 K
作为它的父级);它可能与 E
有许多其他差异:特别是在提交 O
、P
、J
和 K
中发生的任何事情,因为我们已经现在应用 "the changes from N
to E
onto "K
中的内容。
rebase只是重复拷贝
git rebase
作品作者:
- 识别要复制的提交;
- 正在使用临时分支复制它们;和
- 重新指向原来的分支。
如果你 git checkout B
然后 git rebase A
,在步骤 1 中识别的提交是那些在 B
和 A
之间的合并基础之后的提交,直到分支B
。这里的 A
和 B
是因为你当前的分支是 B
而你说 git rebase A
.
练习:看图并识别 B
和 A
的合并基础。可能有点难发现,但是如果我们像这样重新绘制图形呢?
Q--R <-- master
/
...--N--O--P--J--K <-- A
\
E--F--G <-- B
(这张图从拓扑上来说,和我们原来画的图完全一样,但是现在超明显commit N
是merge base .)
简而言之,这些是提交 E
、F
和 G
。所以 rebase 继续第 2 步并复制这三个提交,将副本放在 ("onto") 分支的尖端之后 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
的末端。
为什么这一切都很重要
所有这些复制和改组都发生在您的存储库中,并且不会发生在您存储库的任何其他人的副本中。这意味着任何同事或中央服务器还没有这些副本。如果您 git push
将副本发送到中央服务器,服务器将获得副本——但是如果服务器有原始的、现在被遗弃的提交,并且如果服务器调用它 "branch B
",您将必须强制推送到服务器。
执行此强制推送将使服务器丢弃其原始提交的副本,并放置复制的提交并调用它们 "branch B
"。这是真的即使,在服务器上,在提交G
之后有一个提交H
,分支B
指向提交H
。 换句话说,这可以 "lose" 从服务器提交。 这是第一个问题:你必须与使用服务器的其他人协调,这样你就不会丢失提交。
此外,在执行强制推送后,and/or 如果您的同事正在共享您的存储库(通过 fetching/pulling 来自它),您的同事可能需要调整 他们的 存储库来说明复制提交和移动分支标签。对他们来说,这是一个上游变基,他们必须从中恢复。这是第二个问题:您必须与使用该分支的其他人协调,以便他们知道从上游 rebase 中恢复。
简而言之,请确保您的所有合作开发人员都同意这一点。
如果您有其他人与您一起工作,并且他们共享您将变基的分支,请确保他们都知道。如果您将变基的这些提交 未 发布——如果它们完全是您自己的存储库私有的——那么这种协调根本不需要任何努力,因为没有其他人可以通知,所以没有人可以反对。
正在合并,可能会再次变基
Soon
A
will be merged tomaster
(beforeB
), but not now. Then, when I mergeB
, will it break the reference from havingA
rebased on it?
同样,回答这些问题的方法是从绘制提交图开始。让我们使用新的、重新定位的绘图,然后添加将 B
合并到 master
中的合并提交。由于我们要显示合并,我们需要再次重新绘制图形,以便更容易连接行:
...--N--O--P-Q-R <-- master
\
J--K <-- A
\
E'-F'-G' <-- B
现在我们将 运行 git checkout master
和 git merge A
进行新的合并提交 M
:
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' <-- B
我们不必在此处更改 B
中的任何内容,我们可以像往常一样继续开发它。但是,如果我们想要——并且如果我们所有的合作开发者都同意——我们现在可以再次变基B
,这次是master
。
如果我们 git checkout B; git rebase master
,rebase
将像往常一样从找到 B
和 master
之间的合并基开始。什么是合并基础?查看图表并找到 master
和 B
连接的点。它绝对不是新的合并提交 M
,但也不再是 N
。
分支 B
上的提交是 N
、O
、P
、J
、K
、E'
、F'
和 G'
(以及 N
左侧我们看不到的任何提交)。这部分很简单。棘手的部分是分支 master
上的提交。这些是 N
、O
、P
、Q
、R
和 M
,但 也 J
和 K
。这是因为这两个提交可以通过跟随提交 M
的 second parent.
因此,合并基础(定义为两个分支上的 "closest" 提交)实际上是提交 K
。这正是我们想要的!要将 B
变基到 master
,我们 想要 git 复制 E'
、F'
和 G'
.新副本 E''
、F''
和 G''
将在 M
之后,我们将得到:
E''-F''-G'' <-- B
/
...--N--O--P-Q-R--M <-- master
\ /
J--K <-- A
\
E'-F'-G' [abandoned]
这里真正的教训是绘制图形,因为它会帮助您弄清楚发生了什么。
1至少只有一个这样的点就简单了。在更复杂的图中,可以有多个合并基础。不过,使用复杂的图形进行变基需要的内容比我在这个特定的 SO 帖子中写的要多得多。