我认为我找到了解决方案。假设图表看起来像第二个图中的样子(带有“merge”和“merge2”)。然后执行以下操作:
git replace --graft HEAD HEAD^^ HEAD^2
这将把HEAD的父提交修改为HEAD^^和HEAD^2。
合并提交的第一个父提交始终是目标分支,第二个父提交是源分支(也就是被合并到其他分支的分支)。HEAD^(=merge2)是HEAD的第一个父提交,也是第一个合并提交,所以HEAD^^是第一个合并提交的第一个父提交 – 这应该是第二个合并提交的新的第一个父提交!HEAD^2是merge2的第二个父提交,应保持不变。因此,将HEAD的两个父提交修改为HEAD^^和HEAD^2就可以完成任务。
如果你从另一个角度来思考,这将会很容易。 假设你的主分支叫做“branch-main”,而你的另一个分支叫做“branch-dev”。从图2中,你需要做的是(假设你在branch-main上,而你的HEAD在合并节点上)。
git reset HEAD^ --hard
git merge branch-dev
就是这样。它会给你一个新的合并节点,忽略之前的节点,这就是图3所示的内容。
refs/replace/<hash>
,其中哈希是原始提交的哈希。当Git去查找原始提交时,它会找到refs/replace/
名称,并在最后一刻“移动它的眼睛”到替换而不是使用原始提交。 - torekgit push
和git fetch
)通常忽略替换项。如果让它们也发送替换项,则会将其发送为替换项。其他人默认情况下不会获取到替换项。因此,您可能希望随后使用git filter-branch
,将原始提交重写为新历史记录。Filter-branch遵循替换项(至少默认情况下),因此简单地“复制所见即所得”即可复制嫁接图。 - torekrefs/replace/<hash>
名称,其中名称的<hash>
部分是嫁接前提交的实际哈希ID。refs/replace/*
引用默认情况下不会在克隆和推送中复制,因此替换提交也不会被复制。 - torek