还原使用 'ours' 策略解决的合并提交
Revert merge commit resolved with 'ours' strategy
我的一位同事使用“--strategy=ours”将我们的开发分支合并回功能分支,或者使用一系列有效导致放弃开发更改的操作。
我试图找到一种方法来恢复合并提交以恢复更改,但我无法找到一个简单的方法:
- git revert -m 1 merge-sha1 不起作用,因为第一个父级没有变化
- git revert -m 2 merge-sha1 确实给我们的分支带来了开发变化,但它似乎也摆脱了很多不在分支中的变化开发我们想要保留的内容。
我在网上搜索并找到了一些关于此类或类似情况的文章,但无法找到彻底解决此问题的正确方法。最后,我们在错误合并之前创建了一个新分支,并从头开始。如何以干净的方式解决这种情况?
编辑:
为了更好地解释:
--A--B--C--D--E--F--G--H--I
\ \
D'--E'--F'--M--G'
M
是错误的合并,它丢弃了从 D
到 G
的所有更改。
使用第一个选项 (-m 1
),什么也不会发生。使用第二个选项 (-m 2
),还原似乎删除了 D'
-F'
中发生的更改,同时添加了已删除的更改。
抱歉,忘记补充说 git reset
不是一个选项,因为合并已经被推送到远程仓库并且 git push --force
是不允许的。
如果你想恢复到特定的提交,你只需要 运行 git reset <sha1>
。无论其后的提交类型如何,这都应该有效。 运行 git log
找到合并前的最新提交,然后重置为它。
... I searched online and found some articles about situation like these or similar but couldn't figure out the right way to cleanly resolve this mess. In the end we made a new branch from right before the faulty merge and started from scratch. How could this situation be resolved in a clean way?
实际上 是 正确/干净的方式——虽然你不需要一个新的 branch 本身,因为分支名称是对 Git.
没那么重要
[given this graph]
--A--B--C--D--E--F--G--H--I <-- br1
\ \
D'--E'--F'--M--G' <-- br2
[where] M
is the faulty merge, that discarded all changes from D to G ...
所有 revert 选项通过将 M
与其两个 parent 之一进行比较来工作。由于 M
是 运行 和 --ours
,它的树匹配 F
或 F'
(以第一个 parent 为准):
我不太清楚为什么你用 prime-marks 标记了一些提交(D'-E'-F'
等)但是如果 M
应该 一个真正的合并,而不是 --ours
,你需要 re-run 合并。您可以按照自己喜欢的任何方式执行此操作,但最简单的方法是检查其中一个 parent,这里分别是 G
和 F'
,然后是 运行 git merge
与其另一个 parent 的哈希 ID。一般来说,我建议保留两者的 first- 和 second-parent-ness 属性,所以我会这样做:
git checkout <hash-of-G>
git merge <hash-of-F'>
像往常一样完成合并,如果Git本身没有提交,提交:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2 <-- HEAD
D'--E'--F'--M--G' / <-- br2
\___________/
然后,根据你想看到的,要么cherry-pick G'
,要么强行重置br2
指向结果:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2--G" <-- br2
D'--E'--F'--M--G' /
\___________/
(但这是一个 non-fast-forward 案例,需要 br2
的所有其他用户进行调整),或者您可以在这里放置一个临时名称(标签或分支),git checkout br2
, git merge
临时名称,然后删除临时名称:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2--M3 <-- br2
D'--E'--F'--M--G'-----/---/
\___________/
请注意,生成合并 M3
时的合并基础是 F'
和 G
,因此 git merge
默认情况下会对这两者进行递归合并用作合并基础;然后它将 M2
和 G'
与该虚拟合并基础合并以生成 M3
。您可以使用git merge -s resolve
随机选择F'
或G
之一作为合并基础,如果在创建虚拟合并基础时存在合并冲突,这样可能会不那么混乱。如果你正确地制作了 M2
——对于 "correctly" 的某些定义——无论如何——-s resolve
的结果将是相同的。
最后,Git 不关心如何 您到达最终提交图和这些提交中的快照。 Git 真正关心的是保留提交(保留图形)。 Branch names 仅用于查找提示提交:图中的入口点。各种单独的命令,例如 git diff
和 git cherry-pick
,比较特定的提交,也许从 图中找到它们 ,并从那里做一些有趣的事情,所以你可能希望特定的提交有特定的内容,所以让这些内容尽可能有趣。
与此同时,git merge
本身只是查看图表以找到合并基础,然后进行 two 差异(从合并基础到每个提示提交)以查找更改,然后合并更改。当然也有一些例外:-s ours
使新的合并提交与真正的合并具有相同的图形链接,但完全忽略了两个分支提示之一,因此不必费心寻找合并基础,它只是re-uses 来自 then-current 提交的树。并且,如上文所述,-s recursive
找到 all 合并基础。通常只有一个,所以这没什么特别的,但是有很多方法可以获得多个合并基础,为此 -s recursive
只是合并合并基础以产生一个新的(临时)提交以用作合并基础. (完成 merge-as-a-verb 过程后,它会释放临时提交以供 Git 的常规垃圾收集过程回收。)
我的一位同事使用“--strategy=ours”将我们的开发分支合并回功能分支,或者使用一系列有效导致放弃开发更改的操作。
我试图找到一种方法来恢复合并提交以恢复更改,但我无法找到一个简单的方法:
- git revert -m 1 merge-sha1 不起作用,因为第一个父级没有变化
- git revert -m 2 merge-sha1 确实给我们的分支带来了开发变化,但它似乎也摆脱了很多不在分支中的变化开发我们想要保留的内容。
我在网上搜索并找到了一些关于此类或类似情况的文章,但无法找到彻底解决此问题的正确方法。最后,我们在错误合并之前创建了一个新分支,并从头开始。如何以干净的方式解决这种情况?
编辑:
为了更好地解释:
--A--B--C--D--E--F--G--H--I
\ \
D'--E'--F'--M--G'
M
是错误的合并,它丢弃了从 D
到 G
的所有更改。
使用第一个选项 (-m 1
),什么也不会发生。使用第二个选项 (-m 2
),还原似乎删除了 D'
-F'
中发生的更改,同时添加了已删除的更改。
抱歉,忘记补充说 git reset
不是一个选项,因为合并已经被推送到远程仓库并且 git push --force
是不允许的。
如果你想恢复到特定的提交,你只需要 运行 git reset <sha1>
。无论其后的提交类型如何,这都应该有效。 运行 git log
找到合并前的最新提交,然后重置为它。
... I searched online and found some articles about situation like these or similar but couldn't figure out the right way to cleanly resolve this mess. In the end we made a new branch from right before the faulty merge and started from scratch. How could this situation be resolved in a clean way?
实际上 是 正确/干净的方式——虽然你不需要一个新的 branch 本身,因为分支名称是对 Git.
没那么重要[given this graph]
--A--B--C--D--E--F--G--H--I <-- br1 \ \ D'--E'--F'--M--G' <-- br2
[where]
M
is the faulty merge, that discarded all changes from D to G ...
所有 revert 选项通过将 M
与其两个 parent 之一进行比较来工作。由于 M
是 运行 和 --ours
,它的树匹配 F
或 F'
(以第一个 parent 为准):
我不太清楚为什么你用 prime-marks 标记了一些提交(D'-E'-F'
等)但是如果 M
应该 一个真正的合并,而不是 --ours
,你需要 re-run 合并。您可以按照自己喜欢的任何方式执行此操作,但最简单的方法是检查其中一个 parent,这里分别是 G
和 F'
,然后是 运行 git merge
与其另一个 parent 的哈希 ID。一般来说,我建议保留两者的 first- 和 second-parent-ness 属性,所以我会这样做:
git checkout <hash-of-G>
git merge <hash-of-F'>
像往常一样完成合并,如果Git本身没有提交,提交:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2 <-- HEAD
D'--E'--F'--M--G' / <-- br2
\___________/
然后,根据你想看到的,要么cherry-pick G'
,要么强行重置br2
指向结果:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2--G" <-- br2
D'--E'--F'--M--G' /
\___________/
(但这是一个 non-fast-forward 案例,需要 br2
的所有其他用户进行调整),或者您可以在这里放置一个临时名称(标签或分支),git checkout br2
, git merge
临时名称,然后删除临时名称:
_________
/ \
--A--B--C--D--E--F--G--H--I \ <-- br1
\ \ M2--M3 <-- br2
D'--E'--F'--M--G'-----/---/
\___________/
请注意,生成合并 M3
时的合并基础是 F'
和 G
,因此 git merge
默认情况下会对这两者进行递归合并用作合并基础;然后它将 M2
和 G'
与该虚拟合并基础合并以生成 M3
。您可以使用git merge -s resolve
随机选择F'
或G
之一作为合并基础,如果在创建虚拟合并基础时存在合并冲突,这样可能会不那么混乱。如果你正确地制作了 M2
——对于 "correctly" 的某些定义——无论如何——-s resolve
的结果将是相同的。
最后,Git 不关心如何 您到达最终提交图和这些提交中的快照。 Git 真正关心的是保留提交(保留图形)。 Branch names 仅用于查找提示提交:图中的入口点。各种单独的命令,例如 git diff
和 git cherry-pick
,比较特定的提交,也许从 图中找到它们 ,并从那里做一些有趣的事情,所以你可能希望特定的提交有特定的内容,所以让这些内容尽可能有趣。
与此同时,git merge
本身只是查看图表以找到合并基础,然后进行 two 差异(从合并基础到每个提示提交)以查找更改,然后合并更改。当然也有一些例外:-s ours
使新的合并提交与真正的合并具有相同的图形链接,但完全忽略了两个分支提示之一,因此不必费心寻找合并基础,它只是re-uses 来自 then-current 提交的树。并且,如上文所述,-s recursive
找到 all 合并基础。通常只有一个,所以这没什么特别的,但是有很多方法可以获得多个合并基础,为此 -s recursive
只是合并合并基础以产生一个新的(临时)提交以用作合并基础. (完成 merge-as-a-verb 过程后,它会释放临时提交以供 Git 的常规垃圾收集过程回收。)