【问题标题】:"Amend" a git merge commit after the merged branch is changed“修改”合并分支更改后的 git 合并提交
【发布时间】:2019-12-11 16:51:52
【问题描述】:

假设我已经在 git 中将一个源分支合并到一个目标分支。解决冲突花了很多时间。与此同时,源分支发生了很大变化。现在我必须将源分支的最新状态合并到目标分支中,但是我需要“修改”第一个合并提交,所以我只有一个合并提交而不是两个。如何将两个合并提交压缩在一起?

如果它们是常规提交,我会对 HEAD~ 进行软重置,然后提交 --amend,但在这种情况下,这会导致 merge2 有错误的父级:它不会源自 src 的最后一次提交分支。变基也不起作用,因为我不知道如何将提交变基为合并(即使其具有两个特定的父级)。我也不想从头开始重做整个合并,因为那会花费很多时间。

有没有办法在 git 中做到这一点?

【问题讨论】:

    标签: git merge squash


    【解决方案1】:

    我想我找到了解决方案。假设图形看起来像第二个图中的那样(带有“merge”和“merge2”)。然后这样做:

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

    这会将 HEAD 的父级更改为 HEAD^^ 和 HEAD^2。

    合并提交的第一个父级始终是目标分支,第二个父级是源分支(合并到另一个分支的分支)。 HEAD^ 是 HEAD (=merge2) 的第一个父级,也就是第一个合并提交,所以 HEAD^^ 是第一个合并提交的第一个父级——这应该是第二个合并提交的新的第一个父级! HEAD^2 是 merge2 的第二个父级,应该保持不变。因此,将 HEAD 的两个父级更改为 HEAD^^ 和 HEAD^2 就可以了。

    【讨论】:

    • 注意:这改变了 Git 看到的,但是底层的提交仍然是一样的。移植替换是一个覆盖:提交“merge2”的副本具有更改的第二个父级,因此具有不同的哈希 ID。这个额外的副本附加了名称refs/replace/<hash>,其中哈希是原始提交的哈希。当 Git 去寻找原始提交时,它会找到 refs/replace/ 名称,并在最后一刻“将目光移向”替换而不是使用原始提交。
    • 这一切都没有错,只是要注意传输机制(git push 和git fetch)通常会完全忽略替换。如果您让他们也发送替换件,他们会将其作为替换件发送。其他人默认不会获得替换。所以你可能想在之后使用git filter-branch,将原始提交重写为新的历史记录。 Filter-branch 服从替换(至少在默认情况下),所以一个简单的“复制你所看到的”复制嫁接的图。
    • 我不确定我是否理解。如果父项更改,提交的哈希应该更改,因为父项应该包含在哈希计算中。所以你不能在提交哈希保持不变的情况下改变父母,对吧?我是否正确,替换提交仍然是一个完全正常的提交,但是存在从旧提交到新提交的链接,所以每当您想查询旧提交的属性时,您都会被重定向到新提交?
    • 移植副本是一个新的提交(具有不同的哈希),是的。但是原始(移植前)提交和新的移植提交之间没有联系。替换提交有一个refs/replace/<hash> name,其中name 的<hash> 部分是预移植提交的实际哈希ID。默认情况下,refs/replace/* references 不会在克隆和推送之间复制,因此替换提交也不会。
    【解决方案2】:

    如果换个角度思考,那就容易了。 假设您的主分支称为“branch-main”,而您的另一个分支称为“branch-dev”。从图 2 中您需要做的是(假设您在 branch-main 上并且您的 HEAD 在合并节点上)。

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

    就是这样。它将为您提供一个新的合并节点,忽略前一个,如图 3 所示。 ?

    【讨论】:

      猜你喜欢
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 2015-10-03
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多