如何在 Git 中线性化 "splintered" 合并历史?

How to linearize "splintered" merging history in Git?

一定很明显,但是我没找到办法。每本手册都描述了在现有分支的顶部进行变基或简单的交互式变基,仅此而已。假设,我有一个像这样的菱形 git 历史:

*   949430f Merge commit (D) (HEAD, mybranch)
|\  
| * e6a2e8b (C)
* | 3e653ff (B)
|/  
*   9c3641f Base commit (A)

我想像这样归档历史:

*   949430f Combined commit (BCD)
|  
*   9c3641f Base commit (A)

提交 B 和 C 可能完全被融化或丢弃,没关系,我只想保留结果。我也不想因为讨厌的冲突解决而恢复提交。

这里是我尝试过的东西:

1) 我无法通过简单压缩 B 和 C 来解决这个问题

git rebase -i HEAD~2
...
p 3e653ff (B)
f e6a2e8b (C)
...
Could not apply a91f3a4

嗯,这有点理解,有一些冲突。

2) 我无法通过压缩来压缩它。

git rebase -i -p HEAD~3
...
pick 9c3641f Base commit (A)
f 3e653ff (B)
f e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: unable to match a91f3a4...

3)我连B和C都舍不得

git rebase -i -p -m HEAD~3
...
pick 9c3641f Base commit (A)
#pick 3e653ff (B)
#pick e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: Commit 949430f is merged but option -m is not set.
fatal: cherry-pick failed
Could not pick 4f3e6231b5cecf57434613ca3afd2a21ba375eb9

为什么?这是选项“-m”...

有谁知道如何解决这个问题?

我会先尝试线性化提交图,然后将它们压缩在一起:

$ git checkout commitA -b newbranch
$ git cherry-pick commitB
$ git cherry-pick commitC
[resolve any conflicts]
$ git rebase -i commitA
[change the command for commitC to 'squash']

你要的是git reset --soft(加上). Despite the different circumstances in the question, see this answer by VonC.

git rebase -i 9c3641f^ # 1 before base commit

然后在交互式编辑器中

pick 9c3641f Base commit (A)
pick 3e653ff (B)
fixup e6a2e8b (C)
fixup 949430f Merge commit (D) (HEAD, mybranch)

我实际上希望最后一个不存在,因为根据我的经验,合并提交在交互式变基期间消失了。

这会将 B 和 C 压缩到一个提交中。 D 会消失,而且你真的不想要它,因为它没有添加代码。

这将为您提供所需的输出。您错过的概念是您需要保留第一个提交(选择),但如果您 "fixup" 其他两个,它们将合并到其中。你需要给他们一些东西来合并到不是基本提交的东西中。所以你选择第二个,然后第三个合并到它给你两个提交。

你也可以

git rebase -i 9c3641f

然后就不会在交互式编辑器中看到基本提交,但 pickfixup 对于其余行将是相同的。