还原使用'ours'策略解决的合并提交



我的一位同事将我们的开发分支合并回功能分支,并带有'--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是错误的合并,它丢弃了从DG的所有更改。 使用第一个选项(-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运行的,它的树匹配FF'(以第一个父级为准):

我不太确定为什么你用素数标记(D'-E'-F'等)标记了一些提交,但如果M应该是真正的合并,而不是--ours,你需要重新运行合并。 您可以按照自己喜欢的任何方式执行此操作,但最简单的方法是签出其父级之一,此处分别为GF',然后使用其其他父级的哈希 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 br2git merge临时名称,然后删除临时名称:

_________
/         
--A--B--C--D--E--F--G--H--I        <-- br1
                     M2--M3   <-- br2
D'--E'--F'--M--G'-----/---/
___________/

请注意,生成合并M3时的合并基既F'G,因此默认情况下git merge将执行这两者的递归合并以用作合并基;然后它将针对该虚拟合并基合并M2G'以生成M3。 您可以使用git merge -s resolve随机选择F'G之一作为合并基础,如果在创建虚拟合并基础时存在合并冲突,这可能会不那么混乱。 如果你正确地做了M2——无论如何,对于"正确"的某种定义——-s resolve的结果将是相同的。

最后,Git 并不关心你如何到达最终提交图和这些提交中的快照。 Git 真正关心的是保留提交(保留图形)。 分支名称仅用于查找提示提交:图形的入口点。 各种单独的命令,例如git diffgit cherry-pick,比较特定的提交,也许从图形中找到它们,并且会从那里做有趣的事情,所以你可能希望特定的提交有特定的内容,所以让这些尽可能有趣。

同时,git merge本身只是查看图形以查找合并库,然后执行两次差异(从合并库到每个提示提交)以查找更改,然后合并更改。 当然也有一些例外:-s ours使新的合并提交具有与真正合并相同的图形链接,但完全忽略了两个分支提示之一,因此不必费心寻找合并基础,它只是重用当时提交的树。 而且,如上所述,-s recursive找到所有合并基础。 通常只有一个,所以这没有什么特别的,但是有一些方法可以获取多个合并基,为此-s recursive只是合并合并基以生成一个新的(临时)提交以用作合并基。 (完成合并为动词过程后,它会释放临时提交,由 Git 通常的垃圾回收过程回收。

如果你想恢复到一个特定的提交,你只需要运行git reset <sha1>.无论成功的提交类型如何,这都应该有效。运行git log以查找合并之前的最新提交,然后重置为该提交。

最新更新