恢复失败的合并后重新合并

Ody*_*eus 3 git git-merge git-revert

我在存储库中有两个分支:featuremaster.我将master合并到feature并将结果推送到远程功能分支:

git merge master
Run Code Online (Sandbox Code Playgroud)

因为它包含外部接口的必要更改.比我发现合并冲突被解决了错误,我已经恢复了这个合并:

git revert -n -m 1 78e7ebfa8237
Run Code Online (Sandbox Code Playgroud)

所以我回到功能没有合并.但根据历史合并已经发生并且功能分支已经包含必要的更改.我可以再次尝试合并分支(更仔细地检查冲突,而不是在检查构建之前提交)吗?

tor*_*rek 13

如果您尚未发布错误合并及其还原,则可以删除它们并发布正确的合并.

如果您发布(推送或以其他方式给出)错误合并,您最好的选择可能是通过从错误合并之前创建新分支来计算出正确的合并.例如,假设提交图片段如下所示:

...--i--j--m--w   <-- feature
          /
...---k--l        <-- master
Run Code Online (Sandbox Code Playgroud)

合并提交m是出错的地方,而且w(m颠倒1)是回归m.(注意:如果您有更复杂的历史记录,您可能应该使用不同的策略;请参阅脚注中的链接.)

在这里,想法是j直接检查提交:

git checkout <sha1-of-j>
Run Code Online (Sandbox Code Playgroud)

您现在处于"独立HEAD"模式.此时你可以运行一个新的git merge:

git merge master
Run Code Online (Sandbox Code Playgroud)

这将(基于您提到的合并冲突)停止合并冲突,因为它重复了让您不合并的步骤m.(如果它不会自行停止,请添加--no-commit到merge命令.)

现在正确解决冲突:-) addcommit根据需要.这使得我将调用一个新的合并M,我将绘制如下的新图:

...--i--j------m--w   <-- feature
         \    /
          M  /        <-- HEAD
          | /
         / /
         |/
...---k--l            <-- master
Run Code Online (Sandbox Code Playgroud)

这个新提交M不是(还)在任何分支上,事实上,你并不需要它在任何分支上:你想要的是你在这一点上获得的.

现在我们将这个新的(但是临时的)分支记住提交的SHA-1 M:

git checkout -b temp
Run Code Online (Sandbox Code Playgroud)

(我们之前可以做到这一点; j如果你愿意的话,你可以在"结账提交"步骤中完成;但我还有一些其他未经测试的方法,我将在下面概述).现在让我们回过头来feature创建一个使用M树的新提交,而不是m或者w.有几种方法可以做到这一点,但我会说明这一点,因为它非常简单:

git checkout feature
git rm -r .  # assumes you're in the top level of the work dir
git checkout temp -- .
Run Code Online (Sandbox Code Playgroud)

第一个checkout feature,只是让我们回到分支机构feature.第二清空出指数(下称"下次提交") -这一步才有必要M缺少一些文件(S)是在mw-然后第三提取物提交整个树M到索引和工作树.

现在我们准备提交结果了:

git commit -m "replace everything with corrected merge"
Run Code Online (Sandbox Code Playgroud)

该图现在看起来像这样:

...--i--j------m--w--n   <-- HEAD=feature
         \    /
          M  /           <-- temp
          | /
         / /
         |/
...---k--l               <-- master
Run Code Online (Sandbox Code Playgroud)

提交下的文件与提交下的文件n相同M.我们不再需要提交M和分支temp,所以我们可以简单地删除它们(git branch -D temp),给出:

...--i--j--m--w--n   <-- HEAD=feature
          /
...---k--l           <-- master
Run Code Online (Sandbox Code Playgroud)

如果您对使用较低级别的git命令感到满意,可以使用更简单的(?)方法将树复制M到我们将要添加的新提交feature.特别是我们只需要创建一个父提交的新提交,w其树是那个M.我们可以一步完成,同时仍然在M匿名HEAD,有git commit-tree:

id=$(git commit-tree -p feature -m "message" $(git rev-parse HEAD^{tree}))
Run Code Online (Sandbox Code Playgroud)

假设这是有效的(我没有测试过这个特定的表单,你可能不得不用它git rev-parse来将名称转换feature为原始的SHA-1),我们可以用它git update-ref来制作refs/heads/feature包含id $id:

git update-ref -m "add corrected merge" refs/heads/feature $id
Run Code Online (Sandbox Code Playgroud)

之后简单安全 git checkout feature返回(更新)分支即可.

这是git,有更多的方法可以做到这一点,例如,在匿名分支上,你可以这样做:

git symbolic-ref HEAD refs/heads/feature
git commit -m "replace everything with corrected merge"
Run Code Online (Sandbox Code Playgroud)

这可能比git commit-tree方法更简单(该commit-tree方法正是我首先想到的,因为最近编写了一个复杂的shell脚本,用于commit-tree花哨的repo阴影事物).这种方式的工作方式是symbolic-ref让你回到分支上,feature但根本不接触索引(也不是工作树),所以它/它们仍然匹配树提交M.然后我们使用当前索引以普通方式进行新的提交; 并且由于没有任何东西需要提交M,垃圾收集器最终将删除该提交(但不是树本身,现在可以安全地保存在分支上feature).


1mw事是直接从Linus Torvalds的和朱尼奥·哈默诺被盗.