在合并的分支发生变更后,“修改”Git合并提交

3
假设我已经在Git中将源分支合并到目标分支。解决冲突花费了很多时间。同时,源分支已经发生了很多变化。现在我需要将源分支的最新状态合并到目标分支中,但我需要“修正”第一个合并提交,这样我只有一个合并提交而不是两个。如何将这两个合并提交压缩在一起?
如果它们是普通提交,我会对HEAD~进行软重置,然后提交--amend,但在这种情况下,这将导致merge2具有错误的父级:它不是从src分支的最后一个提交派生的。重新基础也行不通,因为我不知道如何将提交作为合并进行变基(即使它具有两个特定的父级)。我也不想从头开始重新做整个合并,因为那会花费很多时间。
在Git中是否有一种方法可以做到这一点?

2个回答

1

我认为我找到了解决方案。假设图表看起来像第二个图中的样子(带有“merge”和“merge2”)。然后执行以下操作:

git replace --graft HEAD HEAD^^ HEAD^2

这将把HEAD的父提交修改为HEAD^^和HEAD^2。

合并提交的第一个父提交始终是目标分支,第二个父提交是源分支(也就是被合并到其他分支的分支)。HEAD^(=merge2)是HEAD的第一个父提交,也是第一个合并提交,所以HEAD^^是第一个合并提交的第一个父提交 – 这应该是第二个合并提交的新的第一个父提交!HEAD^2是merge2的第二个父提交,应保持不变。因此,将HEAD的两个父提交修改为HEAD^^和HEAD^2就可以完成任务。


注意:这会改变Git“看到”的内容,但基础提交仍然相同。嫁接替换是一个覆盖层:它是带有更改第二个父级的提交“merge2”的副本,因此具有不同的哈希ID。这个额外的副本附加了名称refs/replace/<hash>,其中哈希是原始提交的哈希。当Git去查找原始提交时,它会找到refs/replace/名称,并在最后一刻“移动它的眼睛”到替换而不是使用原始提交。 - torek
这些都没问题,只需注意传输机制(git pushgit fetch)通常忽略替换项。如果让它们也发送替换项,则会将其发送为替换项。其他人默认情况下不会获取到替换项。因此,您可能希望随后使用git filter-branch,将原始提交重写为新历史记录。Filter-branch遵循替换项(至少默认情况下),因此简单地“复制所见即所得”即可复制嫁接图。 - torek
我不确定我理解了。如果父级更改,提交的哈希应该会更改,因为父级应该包含在哈希计算中。所以你不能更改父级而提交哈希保持不变,对吗? 我的理解是替换提交仍然是一个完全正常的提交,但存在从旧提交到新提交的链接,因此每当您想查询旧提交的属性时,您将被重定向到新提交。 - szali
嫁接复制是一个新的提交(具有不同的哈希值),但原始(嫁接前)提交和新的嫁接提交之间没有链接。替换提交有一个refs/replace/<hash> 名称,其中名称<hash>部分是嫁接前提交的实际哈希ID。refs/replace/* 引用默认情况下不会在克隆和推送中复制,因此替换提交也不会被复制。 - torek

0

如果你从另一个角度来思考,这将会很容易。 假设你的主分支叫做“branch-main”,而你的另一个分支叫做“branch-dev”。从图2中,你需要做的是(假设你在branch-main上,而你的HEAD在合并节点上)。

git reset HEAD^ --hard
git merge branch-dev

就是这样。它会给你一个新的合并节点,忽略之前的节点,这就是图3所示的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接