如何用普通提交压缩合并提交?

How to squash a merge commit with a normal commit?

commit b0e5db36ed68d4562275adeb08001b1316a4da52
Merge: ea38baa 8220bb1

commit ea38baa3f46a48722987b8dd3892d2b8d81c4d1a

在这种情况下,我该如何压缩这两个提交

我正在使用

git rebase -i HEAD~2

但这不起作用,因为它删除了合并提交并且不可用于压缩

所以这里要考虑两个因素:

首先,在某些方面 rebase 并不总是能很好地处理合并提交。我会再讲几次。

其次,您并不完全清楚您期望的结果。如果现在你有类似

x -- x -- M -- C <--(master)
 \       /
  A --- B

你想结束

x -- x -- ABC <--(master)

x -- x -- MC <--(master)
 \       /
  A --- B

如果你想要ABC的版本,很简单。虽然 M 没有出现在 rebase 的 TODO 列表中,但所有 M 引入主线的提交(即 AB 在这个例子中)是。所以只需标记 BC 即可 "squash"。唯一要记住的是这是一个历史重写,所以如果你已经推送了任何可以达到 ABMC 的引用,那么一些可能需要清理(请参阅 "recovering from upstream rebase" 下的 rebase 文档)。

如果你要MC的版本,那就麻烦多多了。不是说你不能得到它,但我不认为你可以通过 rebase; 得到它。而且,MC 将是一个 "evil merge",这可能会导致未来的 rebase 尝试出现问题(除其他外)。

默认情况下 rebase 尝试生成线性历史并且不会生成合并提交。您可以使用 --preserve-merges 选项让它生成合并提交,但这与 -i 交互效果不佳(如果您尝试通过这样做修改合并,我预计可能会出现几个问题).

如果你不担心在合并提交中隐藏更改的问题,并且真的想产生像 MC 这样的提交,那么方法是:

首先,将 master ref 移回 M,同时保留索引中 C 的更改。

git checkout master
git reset --soft HEAD^

然后将更改直接重新应用到合并提交

git commit --amend

正如接受的答案所说,git rebase -i(又名 --interactive)支持附加选项 -p(又名 --preserve-merges)。但是,与接受的答案不同,我想指出这实际上似乎可以很好地实现所需的结果,因此如果您这样做 git rebase -i -p HEAD~2 合并提交将出现在交互式 rebase 文件中:

pick abcdeff Merge branch 'feature' into develop
pick abcdefc Extra changes

现在您可以编辑此变基文件以标记第二次提交以进行压缩并完成变基。一切似乎都很好。

但是,我不明白为什么 git 文档 warns against using using -i -p(在某些但不是所有版本的文档中说 -p 已弃用)的复杂性所以你的里程可能会有所不同。似乎主要问题出现在尝试重新排序使用此功能时显示的提交时...所以不要那样做!

The recommended alternative to the deprecated -p option seems to be git rebase -i -r; but that produces a very long and complex interactive rebase file which looks nothing at all like what I am expecting (i.e. the simple rebase file shown as text above).

If anybody can add an answer explaining in any detail whether and why git rebase -i -p is (or isn't) okay in this case, that would be very helpful.