我的一位同事将我们的开发分支合并回功能分支,并带有'--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 来说并不是那么重要。
[给定此图]
--A--B--C--D--E--F--G--H--I <-- br1 D'--E'--F'--M--G' <-- br2
[其中]
M
是错误的合并,丢弃了从 D 到 G 的所有更改......
所有还原选项都通过将M
与其两个父项之一进行比较来工作。 由于M
是用--ours
运行的,它的树匹配F
或F'
(以第一个父级为准):
我不太确定为什么你用素数标记(D'-E'-F'
等)标记了一些提交,但如果M
应该是真正的合并,而不是--ours
,你需要重新运行合并。 您可以按照自己喜欢的任何方式执行此操作,但最简单的方法是签出其父级之一,此处分别为G
和F'
,然后使用其其他父级的哈希 ID 运行git merge
。 一般来说,我建议保留两者的第一和第二父属性,所以我会这样做:
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
___________/
然后,根据您想要看到的内容,挑选G'
并强制重置br2
以指向结果:
_________
/
--A--B--C--D--E--F--G--H--I <-- br1
M2--G" <-- br2
D'--E'--F'--M--G' /
___________/
(但这是一个非快进的情况,需要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
——无论如何,对于"正确"的某种定义——-s resolve
的结果将是相同的。
最后,Git 并不关心你如何到达最终提交图和这些提交中的快照。 Git 真正关心的是保留提交(保留图形)。 分支名称仅用于查找提示提交:图形的入口点。 各种单独的命令,例如git diff
和git cherry-pick
,比较特定的提交,也许从图形中找到它们,并且会从那里做有趣的事情,所以你可能希望特定的提交有特定的内容,所以让这些尽可能有趣。
同时,git merge
本身只是查看图形以查找合并库,然后执行两次差异(从合并库到每个提示提交)以查找更改,然后合并更改。 当然也有一些例外:-s ours
使新的合并提交具有与真正合并相同的图形链接,但完全忽略了两个分支提示之一,因此不必费心寻找合并基础,它只是重用当时提交的树。 而且,如上所述,-s recursive
找到所有合并基础。 通常只有一个,所以这没有什么特别的,但是有一些方法可以获取多个合并基,为此-s recursive
只是合并合并基以生成一个新的(临时)提交以用作合并基。 (完成合并为动词过程后,它会释放临时提交,由 Git 通常的垃圾回收过程回收。
如果你想恢复到一个特定的提交,你只需要运行git reset <sha1>
.无论成功的提交类型如何,这都应该有效。运行git log
以查找合并之前的最新提交,然后重置为该提交。