如何同时重写多个分支的历史记录?

How to rewrite history for multiple branches simultaneously?

使用交互式变基 (git -i rebase ...) 可以在当前分支沿袭的任何地方编辑提交,因此 "rewriting history".

但是,给定的提交可以属于多个分支的沿袭。

例如,假设我有一个具有以下分支结构的回购协议:

A --- B --- C --- D --- F --- G  branch_1*
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

如果活动分支是 branch_1,并且我使用 rebase -i 编辑提交 B,生成的 repo 将如下所示(至少在 GC 发生之前):

  ,-- b --- c --- d --- f --- g  branch_1*
 /
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

请注意,原始 B 继续存在于 branch_2branch_1 的血统中。对每个分支重复该过程,尽管如此乏味,但会导致多次冗余提交,并且原始分支结构将丢失:

  ,-- b --- c --- d --- f --- g  branch_1
 /
A --- B --- C --- D --- F --- G
|            \
|             `-- H --- I --- J
|                        \
|                         `-- K
|\
| `-- b' -- c' -- h --- i --- j  branch_2*
 \
  `-- b'' - c'' - h' -- i' -- k  branch_3*

请注意,bb'b'' 本质上是等效的提交。 cc'c''hh' 以及 ii' 也是如此。 =32=]

有没有半途方便的方法来实现这样的事情:

A --- b --- c --- d --- f --- g  branch_1*
             \
              `-- h --- i --- j  branch_2
                         \
                          `-- k  branch_3

...对 B 提交的修改通过 所有 它所属的谱系传播?

(我更喜欢将更改传播到所有后代存储的解决方案。)

... is there a halfway convenient way to achieve [a sensible result]

没有

有一个命令,git filter-branch可以做到,但方便不到一半,连方便的1/4都不到。大约 1000% 方便。 :-)

新的 git rebase --rebase-merges 机器 显然可以更方便地适应做这种事情,1但目前并未设计为对多个分支名称进行变基。

新的实验性 git filter-repo 有足够的能力做你想做的事,而且可能没有 git filter-branch 那么不方便,但它仍然用核武器打击虫子——在这种情况下,可能是一个中等大小的错误,不仅仅是一只苍蝇,但仍然是严重的矫枉过正。

(我曾经写过自己的实验性的东西来做这种变基,但我从来没有完成它。它做了我需要的,当我需要它的时候。它使用相当于重复 git rebase --onto 操作并且有很多极端情况。)


1关键是能够标记特定的提交,以便在 rebase 复制它们之后,您可以将 < old, new > hash-ID pairs,否则随着 rebase 的进行从一个链跳到另一个链的图形结构。旧的 --preserve-merges 代码无法做到这一点;新的 --rebase-merges 代码可以。一旦你有了这些部分,变基多个分支 "simultaneously" 只是保存多个分支名称以在变基完成后强制调整的问题。然后你让 rebase 列出正确的提交和跳转点。变基操作的主要部分包括复制这些提交。最后,使用旧到新的映射,rebase 可以调整每个分支名称,然后重新连接 HEAD 到你想要的。

剩下的用户界面级别的问题在于选择正确的分支名称集以进行多重变基。

正如你所说,如果你变基branch_1,改变B,你会得到:

  ,-- b --- c --- d --- f --- g  branch_1*
 /
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

然后您可以将 branch_2 变基到 c 上:

git rebase --onto c C

产量:

  ,-- b --- c --- d --- f --- g  branch_1*
 /           \
|             `-- h --- i --- j  branch_2
|
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J
                         \
                          `-- K  branch_3

然后将 branch_3 变基到 i:

git rebase --onto i I

产量:


  ,-- b --- c --- d --- f --- g  branch_1*
 /           \
|             `-- h --- i --- j  branch_2
|                        \
|                         `-- j  branch_3
|
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J
                         \
                          `-- K

这至少会反映您原来的分支结构。