我必须开发分支,然后根据分支B
中的代码找到分支A
。
我想将A
重新定义为B
,以便继续开发B
。
很快A
将合并到master
(B
之前),但现在不合并。然后,当我合并B
时,它是否会破坏A
重新引用它的引用?
我可以在B
上重新master
,一切都会好的,还是我需要做任何特别的步骤?
答案 0 :(得分:1)
请注意,git(以及几乎所有其他版本控制系统)在上调用此基础,而不是中的。
你可能确实做过这种反叛。但是,重要的是要知道当你修改一些提交时,git实际上将它们复制到新的提交。这会影响共享代码的每个人,如果他们已经拥有旧提交。
让我们假设你现在拥有的东西可以这样绘制:
...--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
之前的所有提交)都在分支上{{ 1}};并提交A
,N
,E
和F
(以及G
一如既往的所有提交)都在分支N
上。< / p>
提交B
是分支N
和B
的合并基础,提交master
是分支{{1}的合并基础}和P
。合并基础只是 1 提交之后,分支发散,如果你像我们刚才那样绘制图形就很容易看到。这对您的A
很重要,因为git使用的默认方法是查找此合并基础提交,复制提交 之后的那些提交。 (而且,这意味着在你做一个rebase之前,绘制图形可能是一个好主意,这样你就可以看到你将要做的事情。)
要自己复制单个提交,请使用命令master
。你现在不需要这样做 - rebase会为你做这件事 - 但是知道它是如何工作的好主意,所以让我们简单介绍一下。
在git中,每个提交都是一个完全独立的快照。例如,考虑在分支git rebase
上提交git cherry-pick
。提交F
包含与项目关联的完整源代码树,截至您提交B
时的时间。提交F
和F
也是如此。如果我们比较提交E
与提交G
,我们将看到更改了之间的#/ em>提交E
的树&#34;和#34;提交F
&#34;的树。同样,如果我们比较E
与F
,我们会发现从F
到G
的变化。
将提交转换为一组更改 - 称为 changeset - 允许我们复制提交。例如,假设我们看到从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
中发生的任何差异,因为我们&#39 ;现已应用&#34;从J
到K
的更改到&#34; N
&#34;中的内容。
E
的工作原理是:
如果您K
然后git rebase
,则步骤1中确定的提交是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
和N
。因此,rebase继续执行第2步并复制这三个提交,将副本放在(&#34;到&#34;)分支E
的提示之后(因为你说F
)。
因此,在rebase过程的这一点上,我们现在有了:
G
现在,rebase只做最后一件事,即将当前分支A
重新指向刚刚复制的最后一个提交。这很简单:
git rebase A
原始提交 Q--R <-- master
/
...--N--O--P--J--K <-- A
\ \
\ E'-F'-G' <-- temp
\
E--F--G <-- B
到B
,此时大部分都已消失(它们仍然通过分支 Q--R <-- master
/
...--N--O--P--J--K <-- A
\ \
\ E'-F'-G' <-- B
\
E--F--G [abandoned]
的 reflog 保留但除非你专门看那里,否则你再也看不到它了。新版本E
到G
已添加到分支B
的顶端。
所有这些复制和随机播放都发生在您的存储库中,而不是发生在您的存储库的任何其他人的副本中。这意味着任何同事或集中式服务器还没有这些副本。如果您将副本E'
发送到集中式服务器,服务器将获得副本 - 但如果服务器具有原始服务器,现在已经放弃,则提交,如果服务器调用了该服务器,那么#34;分支G'
&#34;,你必须强制推送到服务器。
执行此强制推送将使服务器丢弃其原始提交的副本,并将复制的提交置于其中并调用那些&#34;分支A
&#34;。这是真的,即使,在服务器上,在提交git push
之后有一个提交B
,其中分支B
指向提交H
。 换句话说,这可能会失去&#34;从服务器提交。这是第一个皱纹:你必须使用服务器与其他人协调,这样你就不会丢失提交。
此外,在进行强制推送后,和/或如果您的同事共享您的存储库(通过提取/拉出存储库),您的同事可能需要将他们的存储库调整为account-commit-and-move-branch-label的帐户。对他们来说,这是一个上游rebase ,他们必须从中恢复。这是第二个问题:你必须与使用分支的其他人协调,以便他们知道从上游的rebase恢复。
如果你有其他人和你一起工作,并且他们正在分享你的分支,那么你只需要确认他们都知道。如果这些提交你将要发布而不是发布 - 如果他们完全私有你自己的存储库 - 那么这种协调根本不需要任何努力,因为没有其他人可以通知,所以没有人可以反对它。
很快
G
将合并到B
(H
之前),但现在不合并。然后,当我合并A
时,它是否会破坏master
重新引用它的引用?
同样,回答这些问题的方法是首先绘制提交图。让我们使用新的,重新设计的绘图,然后添加将B
合并到B
的合并提交。由于我们想要显示合并,我们需要再次重新绘制图形,以便更容易连接行:
A
现在我们将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
,但也是 {{ 1}}和Q
。这是因为可以通过以下提交R
&#39; 第二个父级来达到这两个提交。
因此,合并基础 - 被定义为&#34;最接近&#34;在两个分支上提交 - 实际上是提交M
。这正是我们想要的!要将J
重新定义到K
,我们想要 git来复制M
,K
和B
。新副本master
,E'
和F'
将追溯到G'
,我们会得到这个:
E''
这里的真正教训是绘制图表,因为它可以帮助您弄清楚发生了什么。
1 至少,当有一个这样的点时,它很简单。在更复杂的图形中,可以有多个合并基础。但是,使用复杂的图表进行重新定位需要比我在这个特定的SO帖子中写的要多得多。