Remerge在恢复失败的合并后返回 [英] Remerge after reverting failed merge

查看:125
本文介绍了Remerge在恢复失败的合并后返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  git merge master 

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

  git revert -n -m 1 78e7ebfa8237 

因此,我回到了未合并的功能。但是根据历史合并已经发生和特征分支已经包含必要的变化。我可以尝试再次合并分支(更仔细地检查冲突,而不是在检查构建之前提交)?

解决方案

(推送或以其他方式发出)糟糕的合并,你最好的办法就是通过在错误合并之前创建一个新的分支来制定正确的合并。例如,假设提交图片段如下所示:

  ...-- i  -  j  -  m-- w < - 特征
/
...--- k - l < - 主

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



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

  git checkout< sha1-of- J> 

您现在处于独立HEAD模式。在这一点上,你可以运行一个新的 git merge
$ b

  git merge master 

这会根据您提及的合并冲突停止合并冲突,因为它会重复弄糟你合并的步骤 - m 。 (如果它不会自行停止,请将 - no-commit 添加到合并命令中。)



现在解决冲突:-)并根据需要添加提交。这会产生一个新的合并,我将称之为 M ,然后我将绘制如下新图:

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

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

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

  git checkout -b temp 

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

  git checkout功能
git rm -r。 #假设你在工作目录的顶层
git checkout temp - 。

第一个是结帐功能,只需让我们回到分支功能。第二个清空索引(下一个提交) - 如果 M 缺少中的某些文件, m w - 然后第三个提取整个树从提交 M 到索引和工作树。



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

  git commit -m用正确的合并替换所有内容

图现在看起来像这:

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



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

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






如果您对使用低级别git命令感到满意,可以使用更简单的方法将树从 M 复制到一个新的提交中,我们将把它放在 feature 上。特别是我们只需要做一个新的提交,它的父对象是 w ,其树是 M 。我们可以在 M 和匿名头部之间一步完成, git commit-tree : p>

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

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

  git update-ref -m加正确合并refs / heads / feature $ id 


之后可以简单地安装 git checkout feature )分支。



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

  git symbolic-ref HEAD refs / heads / feature 
git commit -m用cor替换所有内容rected merge

这可能比 git commit-tree

code>方法(> commit-tree 方法正是我之前想到的,因为最近编写了一个复杂的shell脚本,它使用提交树为幻想回购阴影事物)。它的工作方式是 symbolic-ref 可以让你回到分支功能上,但不会触及索引(也不会触及索引工作树),所以它/它们仍然与提交 M 的树相匹配。然后我们用普通的方式做一个新的提交,使用当前的索引;由于没有任何东西指向提交 M ,所以垃圾收集器最终将删除该提交(但不是树本身,现在它已安全地保存在分支 feature )。






1 m w 事情是直接从Linus Torvalds和Junio Hamano盗取


I have two branches in repository: feature and master. I have merged master into feature and pushed result to remote feature branch:

git merge master

because it contains necessary changes of external interfaces. Than I have discovered that merge conflicts were resolved wrong and I have reverted this merge with:

git revert -n -m 1 78e7ebfa8237

So I'm back on feature not merged. But according to history merge already happened and feature branch already contains necessary changes. Can I try merge branches again (inspecting conflicts more carefully and not commiting before checking build)?

解决方案

If you have not published the bad merge and its reversion, you can remove them and publish a correct merge instead.

If you have published (pushed or otherwise given out) the bad merge, your best bet is probably to work out a correct merge by creating a new branch starting from just before the bad merge. For instance, suppose the commit graph fragment looks like this:

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

where merge commit m is the one that went wrong, and w (m upside down1) is the reversion of m. (Note: if you have a more complex history, you probably should use a different strategy; see the link in the footnote.)

Here, the idea would be to check out commit j directly:

git checkout <sha1-of-j>

You are now in "detached HEAD" mode. At this point you can run a new git merge:

git merge master

This will (based on your mention of merge conflicts) stop with a merge conflict, since it's repeating the step that got you bad-merge-m. (If it won't stop on its own, add --no-commit to the merge command.)

Now resolve the conflicts correctly this time :-) and add and commit as needed. This makes a new merge which I'll call M, and I will draw the new graph like this:

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

This new commit M is not (yet) on any branch, and in fact, you don't really need it to be on any branch: what you want is the tree you obtained at this point.

Now we'll make this a new (but temporary) branch to remember the SHA-1 of commit M:

git checkout -b temp

(we could have done this earlier; you can do it at the "check out commit j" step if you like; but I have some other, un-tested, methods in mind that I'll outline below). Now let's get back on feature and make a new commit that uses M's tree, rather than that of m or w. There are several ways to do this, but I will illustrate this one since it's pretty simple:

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

The first of these, checkout feature, simply gets us back on branch feature. The second empties out the index (the "next commit")—this step is only necessary if M is missing some file(s) that are in m and w—and then the third extracts the entire tree from commit M into the index and work-tree.

Now we're ready to commit the result:

git commit -m "replace everything with corrected merge"

The graph now looks like this:

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

The files under commit n are the same as those under commit M. We no longer need commit M and branch temp at all, so we can simply delete them (git branch -D temp), giving:

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


If you're comfortable with using lower level git commands, there's a simpler (?) way to copy the tree from M to a new commit we'll put on feature. In particular we just need to make a new commit whose parent is w and whose tree is that of M. We can do that in one step while still on M and the anonymous HEAD, with git commit-tree:

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

Assuming this works (I haven't tested this particular form and you might have to use git rev-parse to convert the name feature to a raw SHA-1), we can then use git update-ref to make refs/heads/feature contain id $id:

git update-ref -m "add corrected merge" refs/heads/feature $id

after which it's safe to simply git checkout feature to get back on the (updated) branch.

This being git, there are more ways to do it, e.g., when on the anonymous branch, you could do this:

git symbolic-ref HEAD refs/heads/feature
git commit -m "replace everything with corrected merge"

which is probably simpler than the git commit-tree method (the commit-tree method is just what I thought of first, due to having recently written a complicated shell script that used commit-tree for a fancy repo shadowing thing). The way this works is that the symbolic-ref puts you back on branch feature but does not touch the index (nor work-tree) at all, so it/they still match the tree for commit M. Then we make a new commit in the ordinary way, using the current index; and since nothing remains to point to commit M, the garbage-collector will eventually delete that commit (but not the tree itself, which is now safely saved on branch feature).


1The m and w thing is stolen directly from Linus Torvalds and Junio Hamano.

这篇关于Remerge在恢复失败的合并后返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆