我可以安全地将一个分支重新绑定到另一个分支然后再掌握吗?

时间:2016-03-16 21:13:42

标签: git merge branch rebase

我必须开发分支,然后根据分支B中的代码找到分支A

我想将A重新定义为B,以便继续开发B

很快A将合并到masterB之前),但现在不合并。然后,当我合并B时,它是否会破坏A重新引用它的引用?

我可以在B上重新master,一切都会好的,还是我需要做任何特别的步骤?

1 个答案:

答案 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...)。因此,NR的提交是master(以及隐藏在N左侧的所有提交);提交NOPJK(以及N之前的所有提交)都在分支上{{ 1}};并提交ANEF(以及G一如既往的所有提交)都在分支N上。< / p>

合并基地

提交B是分支NB合并基础,提交master是分支{{1}的合并基础}和P。合并基础只是 1 提交之后,分支发散,如果你像我们刚才那样绘制图形就很容易看到。这对您的A很重要,因为git使用的默认方法是查找此合并基础提交,复制提交 之后的那些提交。 (而且,这意味着在你做一个rebase之前,绘制图形可能是一个好主意,这样你就可以看到你将要做的事情。)

复制提交

要自己复制单个提交,请使用命令master。你现在不需要这样做 - rebase会为你做这件事 - 但是知道它是如何工作的好主意,所以让我们简单介绍一下。

在git中,每个提交都是一个完全独立的快照。例如,考虑在分支git rebase上提交git cherry-pick。提交F包含与项目关联的完整源代码树,截至您提交B时的时间。提交FF也是如此。如果我们比较提交E与提交G,我们将看到更改了之间的#/ em>提交E的树&#34;和#34;提交F&#34;的树。同样,如果我们比较EF,我们会发现从FG的变化。

将提交转换为一组更改 - 称为 changeset - 允许我们复制提交。例如,假设我们看到从FG发生了什么。然后假设我们检查提交N并使进行相同的更改,然后在新的临时分支上提交它:

E

我调用了新提交K,而不是给它一个新的单个字母,因为它是提交...--N--O--P--Q--R <-- master \ \ \ J--K <-- A \ \ \ E' <-- temp branch \ E--F--G <-- B 副本。当然,它与提交E'不完全相同相同。首先,它有一个不同的父级(它具有提交E作为其父级);它可能与E存在许多其他差异:特别是在提交KEOP中发生的任何差异,因为我们&#39 ;现已应用&#34;从JK的更改到&#34; N&#34;中的内容。

Rebase只是重复复制

E的工作原理是:

  1. 识别要复制的提交;
  2. 使用临时分支复制它们;和
  3. 重新指向原始分支。
  4. 如果您K然后git rebase,则步骤1中确定的提交是git checkout Bgit rebase A之间的合并基础之后的提交,直到分支的提示{ {1}}。这里的BA是因为您当前的分支是B,而您说A

    练习:查看图表并确定BB的合并基础。可能有点难以发现,但是如果我们像这样重新绘制图形呢?

    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 保留但除非你专门看那里,否则你再也看不到它了。新版本EG已添加到分支B的顶端。

    为什么这一切都很重要

    所有这些复制和随机播放都发生在您的存储库中,而不是发生在您的存储库的任何其他人的副本中。这意味着任何同事或集中式服务器还没有这些副本。如果您将副本E'发送到集中式服务器,服务器将获得副本 - 但如果服务器具有原始服务器,现在已经放弃,则提交,如果服务器调用了该服务器,那么#34;分支G' &#34;,你必须强制推送到服务器。

    执行此强制推送将使服务器丢弃其原始提交的副本,并将复制的提交置于其中并调用那些&#34;分支A&#34;。这是真的,即使,在服务器上,在提交git push之后有一个提交B,其中分支B指向提交H换句话说,这可能会失去&#34;从服务器提交。这是第一个皱纹:你必须使用服务器与其他人协调,这样你就不会丢失提交。

    此外,在进行强制推送后,和/或如果您的同事共享您的存储库(通过提取/拉出存储库),您的同事可能需要将他们的存储库调整为account-commit-and-move-branch-label的帐户。对他们来说,这是一个上游rebase 他们必须从中恢复。这是第二个问题:你必须与使用分支的其他人协调,以便他们知道从上游的rebase恢复。

    简而言之,请确保所有合作开发人员都可以。

    如果你有其他人和你一起工作,并且他们正在分享你的分支,那么你只需要确认他们都知道。如果这些提交你将要发布而不是发布 - 如果他们完全私有你自己的存储库 - 那么这种协调根本不需要任何努力,因为没有其他人可以通知,所以没有人可以反对它。

    合并,也许再次重新定位

      

    很快G将合并到BH之前),但现在不合并。然后,当我合并A时,它是否会破坏master重新引用它的引用?

    同样,回答这些问题的方法是首先绘制提交图。让我们使用新的,重新设计的绘图,然后添加将B合并到B的合并提交。由于我们想要显示合并,我们需要再次重新绘制图形,以便更容易连接行:

    A

    现在我们将Bmaster运行以进行新的合并提交...--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

    如果我们BB将照常开始寻找mastergit checkout B; git rebase master之间的合并基础。什么是合并基础?查看图表,找到rebaseB加入的点。它绝对不是新的合并提交master,但它不再是master

    分支B上的提交有MNBNOPJK(以及我们无法看到E'左侧的任何提交)。这部分很简单。棘手的部分是分支F'上的提交。这些是G'NmasterNOP,但也是 {{ 1}}和Q。这是因为可以通过以下提交R&#39; 第二个父级来达到这两个提交。

    因此,合并基础 - 被定义为&#34;最接近&#34;在两个分支上提交 - 实际上是提交M。这正是我们想要的!要将J重新定义到K,我们想要 git来复制MKB。新副本masterE'F'将追溯到G',我们会得到这个:

    E''

    这里的真正教训是绘制图表,因为它可以帮助您弄清楚发生了什么。

    1 至少,当有一个这样的点时,它很简单。在更复杂的图形中,可以有多个合并基础。但是,使用复杂的图表进行重新定位需要比我在这个特定的SO帖子中写的要多得多。