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

时间:2015-01-28 10:49:49

标签: git git-merge git-revert

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

git merge master

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

git revert -n -m 1 78e7ebfa8237

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

2 个答案:

答案 0 :(得分:12)

如果发布了错误合并及其还原,则可以删除它们并发布正确的合并。

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

...--i--j--m--w   <-- feature
          /
...---k--l        <-- master

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

这里的想法是直接检查提交j

git checkout <sha1-of-j>

您现在处于“超级HEAD”模式。此时,您可以运行新的git merge

git merge master

这将(基于你提到的合并冲突)停止合并冲突,因为它正在重复让你合并错误的步骤 - m。 (如果它不会自行停止,请将--no-commit添加到合并命令。)

现在正确解决冲突:-)并根据需要addcommit。这会产生一个新的合并,我称之为M,我会像这样绘制新图:

...--i--j------m--w   <-- feature
         \    /
          M  /        <-- HEAD
          | /
         / /
         |/
...---k--l            <-- master

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

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

git checkout -b temp

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

git checkout feature
git rm -r .  # assumes you're in the top level of the work dir
git checkout temp -- .

其中第一个checkout feature,让我们回到分支feature。第二个清空索引(“下一次提交”) - 仅当M缺少mw中的某些文件时才需要执行此步骤 - 然后第三个从提交M中提取整个树到索引和工作树中。

现在我们已准备好提交结果:

git commit -m "replace everything with corrected merge"

图表现在看起来像这样:

...--i--j------m--w--n   <-- HEAD=feature
         \    /
          M  /           <-- temp
          | /
         / /
         |/
...---k--l               <-- master

提交n下的文件与提交M下的文件相同。我们不再需要提交M和分支temp,因此我们只需将其删除(git branch -D temp),即可:

...--i--j--m--w--n   <-- HEAD=feature
          /
...---k--l           <-- master

如果您对使用较低级别的git命令感到满意,可以使用更简单的(?)方法将树从M复制到我们将放在feature上的新提交。特别是我们只需要创建一个父提交为w且其树为M的新提交。我们可以在M和匿名HEAD的git commit-tree上一步完成:

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

假设这有效(我没有测试过这个特定的表单,你可能不得不使用git rev-parse将名称feature转换为原始SHA-1),然后我们可以使用{{1要使git update-ref包含ID refs/heads/feature

$id

之后只需git update-ref -m "add corrected merge" refs/heads/feature $id 即可返回(更新)分支。

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

git checkout feature

这可能比git symbolic-ref HEAD refs/heads/feature git commit -m "replace everything with corrected merge" 方法更简单(git commit-tree方法正是我首先想到的,因为最近写了一个复杂的shell脚本,用commit-tree来表示repo shadowing thing)。这种方式的工作方式是commit-tree会让你回到分支symbolic-ref但是根本不会触及索引(也不是工作树),所以它/它们仍然匹配提交的树{{1 }}。然后我们使用当前索引以普通方式进行新的提交;并且由于没有任何内容指向提交feature,垃圾收集器最终将删除该提交(但不是树本身,现在已安全地保存在分支M上)。


1 Mfeature的事情是stolen directly from Linus Torvalds and Junio Hamano

答案 1 :(得分:1)

如果执行git revert,它将撤消合并,因此我认为该功能不包含必要的更改。我将在合并之前进入状态,只有一些额外的git日志。所以你可以自由地合并它。 但是,如果你不想要额外的git日志,你可以使用git reset。

  1. 检查您之前想要的状态:git log

  2. git reset {commit-id-founded}

  3. 解决您的冲突

  4. 再次合并