从 git 历史中抹去整个提交链?

Obliterate entire chain of commits from git history?

我有一个很奇怪的问题。在尝试迁移到 Github 的大型文件存储并尝试从它迁移出去时遇到一些不幸之后,我现在有一个非常混乱的 git 拓扑,如下所示:

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

现在,C 与 C' 完全相同,B 与 B' 完全相同,依此类推一直回到初始提交。如果我这样做 "git log",我基本上会看到 D 之前所有内容的重复提交。D 本身是一个空合并。

有没有办法完全删除A'、B'、C',让我的历史变成这样?

A - B - C - E - F

是的。您可以将 E - F 变基到 C.

git rebase --onto <new-base> <exclusive-start> <inclusive-end>

因为起点是独占的(它不会变基)我们从 D 开始到 F 结束。(这使得变基在上面的分支变得容易分支机构)。

git rebase --onto C D F

你会得到这个。

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

只要没有任何内容指向 F,A' - F 最终将被垃圾回收。

鉴于 D 未引入任何更改,您可以通过多种方式进行更改。

rebase 会起作用(正如 Schwern 所建议的)。 "Reparenting" 也可以。

因为变基是 "more familiar",我认为有些人可能更喜欢这种方法。另一方面,在某些情况下,变基变得复杂可能会引入错误;出于这个原因,我更喜欢在两者预期相同的情况下重新设置。

假设您显示的历史记录是 master 分支的历史记录(并且从 D 开始的任何内容都无法从任何其他分支访问),那么 rebase 将是

git rebase --onto C D master

用解析相应提交的表达式替换 CD(即提交 ID,或者您显示的历史图中 Cmaster~3 ).

请注意,我使用分支名称而不是提交 ID 或其他表达式来标识 F。这样rebase操作会自动移动分支。

如果在 D 之后有合并(即使它们全部折叠回一个仍然当前的分支),或者如果有多个分支指向您正在移动的历史记录,那么这些是在最明显的情况下,您可能会考虑重新设置父级。

在这种情况下,您将使用 git filter-branch。有几种方法可以做到;请参阅 parent-filter 下的 git filter-branch 文档 (https://git-scm.com/docs/git-filter-branch);有一些示例具体说明了如何重新提交提交。