修改基本分支并立即重新绑定所有子项

时间:2017-02-11 20:46:54

标签: git

我有这样的事情:

 A - E //branch_1
      \
       B' - C' //branch_2
             \
              D' //branch_3

我想得到这样的东西:

   Lukas 10
   Matthias 8
   Sven 5
   Fernando 10

我想立刻执行一个命令并重新绑定所有分支,所以我不必逐个改变它们。这可能吗?

3 个答案:

答案 0 :(得分:4)

简短的回答:不,它不可能......但是你可以最大限度地减少你必须做的工作量。关于减少工作的长期答案如下。

理解这一点的关键是Git的分支名称 - 您的示例中的名称branch_1branch_2branch_3是只是标识符"指向"一个特定的提交。它是构成实际分支的提交本身。有关详细信息,请参阅What exactly do we mean by "branch"?同时,git rebase复制某些提交的做法是什么,新副本通常在新基础上进行(因此"重新基"。)

在您的特定情况下,只有一个提交链需要复制。这是B--C--D链。如果我们剥离所有标签(分支名称),我们可以这样绘制图形片段:

A--E
 \
  B--C--D

您的任务是将B--C--D复制到B'--C'--D',类似于BD,但是E之后而不是A之后}。我将它们放在最顶层,这样我们就可以保留原始的B--C--D链:

     B'-C'-D'
    /
A--E
 \
  B--C--D

一旦您制作了副本,您就可以更改标签,使它们指向副本,而不是指向原件;现在我们需要向上移动D',以便我们可以将branch_2指向C'

          D'   <-- branch_3
         /
     B'-C'     <-- branch_2
    /
A--E           <-- branch_1

这需要至少两个Git命令才能完成:

  1. git rebase,将B-C-D复制到B'-C'-D'并将branch_3移至指向D'。通常这将是两个命令:

    git checkout branch_3 && git rebase branch_1
    

    但你可以使用一个Git命令实际执行此操作,因为git rebase可以选择执行初始git checkout

    git rebase branch_1 branch_3
    
  2. git branch -f,重新指向branch_2

    我们知道(从我们仔细的图表向我们看到,我们可以执行git rebase branch_3 branch_2来复制所有提交,branch_3指向提交&#34退后一步&#34;从branch_2指向的提交。也就是说,在开始时,C名称提交branch_3D名称提交branch_2。因此,一旦我们完成所有工作,C'需要提名branch_3

    由于 从旧branch_3的提示后退一步,因此必须从之后的新rebase的提示后退一步。 1 现在我们已完成B'-C'-D'并拥有branch_2链,我们只需指示Git将标签branch_3移动到距离{{1}的任何地方一步点:

    git branch -f branch_2 branch_3~1
    
  3. 因此,对于这种情况,它需要至少两个Git命令(如果您更喜欢单独的git checkout,则需要三个)。

    请注意,即使我们只移动/复制两个分支名称,也可能需要更多或不同的命令。例如,如果我们开始:

    F--J        <-- br1
     \
      G--H--K   <-- br2
          \
           I    <-- br3
    

    并希望复制所有G-H-(K;I),我们无法使用一个git rebase命令执行此操作。我们可以做的是首先重复br2br3,复制四个提交中的三个;然后将git rebase --onto <target> <upstream> <branch>与剩余的分支一起使用,以复制剩余的一个提交。

    (事实上,git rebase --onto是最常见的形式:我们总是可以用一系列git rebase --onto <target> <upstream> <branch>命令完成整个工作,每个分支一个。这是因为{{1}确实两个事情:(1)复制一些提交,可能为空;(2)将分支标签移动到la git rebase。复制的集合由{的结果确定{1}} - 请参阅下面的gitrevisions和脚注1 - 并且git branch -f设置了复制位置;并且分支的目的地是<upstream>..HEAD完成后的任何地方。如果副本集为空,--onto会在HEAD目标上结束。所以似乎就像一个简单的(ish)脚本可以完成所有的工作......但请参阅脚注1。)

    1 然而,这假设HEAD实际上最终复制所有提交。 (这个假设的安全程度因所讨论的基础而变化很大。)

    实际上,虽然要复制的初始提交集是通过运行--onto - 或其等价物来确定的,但实际上,通过为每个提交计算git rebase,可以立即进一步削减该初始集在&#34;复制&#34;并且不需要复制,因为现在将是上游&#34;范围。也就是说,rebase代码使用git rev-list --no-merges <upstream>..HEADgit patch-id结合而不是<upstream>..HEAD 2 所以我们不仅省略了合并提交,还省略了已经提交的提交上游。

    我们可以编写一个自己执行此操作的脚本,以便我们可以找到每个分支名称在我们希望重新绑定的分支集合中的相对位置。 (我之前做过大部分的实验。)但还有另一个问题:在挑选樱桃的过程中,由于解决冲突,某些提交可能会变空,你会{{1他们。此更改剩余复制提交的相对位置。

    这最终意味着除非<upstream>...HEAD增加一点,记录哪些提交映射到哪些新提交以及哪些提交完全丢弃,否则无法完全正确,完全可靠的multi-rebase脚本。我认为可以在不修改Git本身的情况下使用--right-only --cherry-pick reflog来充分接近:如果有人启动这种复杂的rebase,这只会出错,但是在其中间,会有一些{{1} } s等然后恢复rebase。

    2 对于某些形式的git rebase --skip而言,这种情况确实如此。生成列表的代码取决于您是否使用git rebase和/或HEAD和/或git reset --softnon-interactive git am based rebase使用:

    git rebase

    --interactive通过使用的任何命令(cherry-pick或format-patch)传递给--keep-empty代码,以便它可以获得提交ID的右侧列表,与预先采摘的樱桃&#34;从对称差异中删除。

    交互式rebase相当复杂(!)。

答案 1 :(得分:0)

为了至少找出哪些分支,您必须在初始rebase之后更新,您可以运行

$ git branch --contains <commit A>

答案 2 :(得分:0)

此问题是How do I rebase a chain of local git branches?

的超集

我今天使用的解决方案是一个名为git-chain的工具,旨在解决此问题。

在您的示例中,您可以指定链条

git chain setup -c myfeature branch1 branch2 branch3

建立此链后,您可以向branch1进行新的提交,然后运行git chain rebase -c myfeature,该工具会找出所有引用并为您很好地重新设置所有基准。

作为一项额外的好处,它还计算并处理对branch1branch2branch3的任何修订或新提交。