使用Git rebase压缩旧提交
假设我有这样一个git历史记录:使用Git rebase压缩旧提交,git,Git,假设我有这样一个git历史记录: -- A -- B -- C -- D -- \ / -----E----- 有没有相对快速的方法将B和C压缩成一个提交 我希望我的最终历史看起来像: -- A -- BC' -- D' -- \ / ----E---- 使用普通的重定基来压缩B和C是很容易的——似乎让新的提交取代B和C成为祖先或D是很麻烦的 当一个指向D的分支签出后,运行git-rebase-i-master(a
-- A -- B -- C -- D --
\ /
-----E-----
有没有相对快速的方法将B和C压缩成一个提交
我希望我的最终历史看起来像:
-- A -- BC' -- D' --
\ /
----E----
使用普通的重定基来压缩B和C是很容易的——似乎让新的提交取代B和C成为祖先或D是很麻烦的
当一个指向D的分支签出后,运行git-rebase-i-master(a的前身),并选择挤压C时,生成的历史如下所示:
A -- BC' -- E'
\
--- E
假设此图代表您的主分支:
master: A <- B <- C <- D (what you have)
master: A <- S <- D (what you want)
完成后,键入以下内容以完成重新基准:
git rebase --continue
通过选择提交B的squash
,它将把提交B合并到提交C中,给您留下您想要的内容。请记住,挤压B
和C
提交可能会产生合并冲突
使用普通的重定基来压缩B和C是很容易的——似乎让新的提交取代B和C成为祖先或D是很麻烦的
让新的提交取代B和C成为D的祖先不仅很容易,而且是默认行为。我不确定使用git rebase是否不可能做到这一点(使用--preserve
),而是使用git filter branch
,通过过滤,您可以完全删除提交B
。然后,过滤器序列将C
的树复制到C'
,并使C'
的父级成为A
,将D
的树复制到D'
,并使D'
的父级(仍然有两个)分别成为E
和C'
注意,当我在这里调用副本C'
时,它有C的树,它也包括B
中更改的内容。因此,您可以正确地将其命名为BC'
,这样您就可以得到您所绘制的内容
git filter-branch --commit-filter '
if [ "$GIT_COMMIT" = id-of-B ]; then skip_commit "$@";
else git commit-tree "$@"; fi' branchname
(在此处填写B的ID,并填写一个适当的正引用;使用branchname~5..branchname或类似工具来减少迭代的提交次数,选择~
值,使筛选器分支看到所需内容,但足够低,不会“复制”根本不会更改的提交)
您还可以使用较低级别的git命令(特别是两个git提交树
命令,然后是强制分支移动)来实现这一点。考虑到下面的脚注1,这可能会变得更容易(取决于D
是否是所讨论分支的最尖端提交,以及您对过滤器分支的舒适度)
1正如任何带有git过滤器分支的东西都可以说是“容易的”…:-)即使您完全理解了它,仍然需要进行后期过滤清理。您想要的是什么?我当然需要使用它-但是如果我使用更一般的用例,我总是在分支顶端使用新的B+C组合提交(或者--on分支)或默认选项。我想让他们留在他们的位置上。这应该能满足你的需要。@nihilon,恐怕不行:(git-rebase-i A-p
然后将C
从pick
更改为fixup
此答案不起作用。请在作为答案发布之前尝试您建议的命令。master
在git-rebase
中不正确,并合并提交(D
)将不会以您为初学者提供的选项显示在交互式重基中。我担心这并不能完全满足我的要求-B和C提交仍然会出现在我的历史记录中,因为C是D的前身。您的示例简化了这一点,从而使git垃圾回收器删除不再引用的提交。请请更新您的问题,以便清楚地知道您想要什么。将新的组合提交设置为D的祖先仅是当D除了要组合的提交之外没有其他祖先时的默认行为。这不适用于我的示例,我相信D也必须成为新的提交(D’)为了反映这样一个事实,即它的祖先集合需要从{C,F}到{BC',F}请尝试做一个我在回答中列出的“香草”重基。如果你没有得到预期的结果,那么更新你的问题,说明为什么正常的重基不会按我们预期的方式运行。
git filter-branch --commit-filter '
if [ "$GIT_COMMIT" = id-of-B ]; then skip_commit "$@";
else git commit-tree "$@"; fi' branchname