Git:重新定义冲突的合并提交

时间:2015-02-20 11:08:47

标签: git merge conflict rebase

完成主题分支的处理后,我将主题分支合并为主分支,如下所示:

          o---*---o---o topic
         /             \
o---o---o---*---o---o---+ master

标有'*'的提交修改了相同的代码,因此合并导致合并提交中解决的合并冲突(标有'+')。

当我合并并解决冲突时,我的同事将新的提交推送到主人(标记为'n'),导致以下历史记录:

          o---*---o---o topic
         /             \
o---o---o---*---o---o---+ master
                    \
                     n---n origin/master

现在,推送我的本地主分支当然会导致错误,因为它没有快进,所以我有两个选择:

  1. 丢弃我的工作,将master重置为origin / master并重做合并。我想避免这种情况,因为我必须重新解决冲突。

  2. 将master master重新导入origin / master并推送。这就是我的问题:执行此rebase(即使使用-p开关)也不能顺利运行,合并提交再次显示相同的冲突,即使新提交('n')没有改变任何触及的内容由主题分支。因此,我必须在rebase期间再次解决冲突,并且与选项1具有相同的结果。

  3. 我想要实现的是重新定义合并提交'+',而不必再次解决冲突:

              o---*---o---o-------- topic
             /                     \
    o---o---o---*---o---o---n---n---+ master & origin/master
    

    编辑:

    启用了rerere开关,但似乎没有任何帮助;除了将config.rerere设置为true以解决我的问题之外,我还需要做些什么吗?

    编辑2:

    将merge-commit('+')合并到origin / master也会起作用(如评论和答案中所提出的那样),但会导致一种丑陋的历史记录,我希望通过一次合并避免只提交。

4 个答案:

答案 0 :(得分:1)

第一种方式是最好的。撤消您的合并并重做它以使您的同事更改为合并提交。但是你不需要抛弃这些变化。

由于您知道您的同事的更改并未影响您解决冲突的文件。您可以创建一个新的分支(我们称之为conflict-fix)来自你当前的主人状态。重置您的分支并重做合并。

而不是使用git mergetool或您使用的任何编辑器。您可以使用git checkout conflict-fix -- <file names>将文件从其他分支转换为master。 git add文件并提交以完成合并。然后,您可以删除conflict-fix分支。

这很容易做到,并且会导致您正在寻找的单个合并提交,并允许您推送您的更改。如果新提交影响了您解决的文件,则无论如何都必须重做它们。

<强> 修改

我对git rerere并不完全熟悉,但这应该有效。但是根据您的评论,您不需要变基。您仍然会撤消合并提交,git fetch更新并重新执行合并。您只需调用git rerere命令即可​​解决文件中的冲突。你的树看起来像这样:

          o---*---o---A topic
         /             \
o---o---o---*---o---o---+ master
                 \
                  n---n origin/master

您将执行以下操作:

git reset --hard A
git checkout master
git pull
git merge topic
git rerere
//Fix other conflicts
git push

你应该最终得到:

          o---*---o---o-------- topic
         /                     \
o---o---o---*---o---o---n---n---+ master & origin/master

不需要任何改变。

http://git-scm.com/docs/git-rerere

答案 1 :(得分:0)

如果你在master之上重新定位主题,然后将master重置为上一次提交并从远程提取,那么你将拥有这个:

          o---*---o---o 
         /             \
o---o---o---*---o---o---+ topic
                    \
                     n---n master & origin/master

然后您将主题合并到master中,从而导致此(标记为&#39;#&#39;的新合并提交):

          o---*---o----o 
         /              \
o---o---o---*---o---o----+ topic
                    \     \
                     n--n--# master

这是否会引起冲突?它会对你有用吗?

答案 2 :(得分:0)

rerere是避免这种麻烦的方法,但是如果你在第一次合并之前没有启用它,它就无法帮助你。您可以知道它是否已启用,因为它会提供有关记录preimage&#39;

的消息

我最近自己遇到了这个问题,因为我有一台新的开发机器,忘了在丑陋的合并之前启用rerere。对于这种情况,没有一个很好的git解决方案,但以下是我能想出的最简单的恢复情况。

  1. 确保您的工作目录完全是合并结果(git reset HEAD --hard)并从合并提交中复制源树安全
  2. 在任何合并提交之前重置你的本地分支(git reset --hard master~或git reset HEAD~n,其中n是你需要走的距离)
  3. git pull
  4. git merge topic
  5. 将源文件复制回工作树覆盖。
  6. git mergetool(处理任何已删除vs已修改的冲突)
  7. 提交并推送
  8. 由于我们正在使用gerrit,我还确保Change-Id与我之前的合并提交相同,因此我可以验证没有出错。

答案 3 :(得分:0)

据我所了解/了解的rerere,如果您使用rerere-train.sh脚本记录您已经提交的解决方案,它应该可以为这种确切情况提供帮助。

因此,以下方法可以解决问题:

  1. 使用args <merge commit>^..<current branch>→现在rerere运行脚本,您知道完全/仅此合并的冲突解决方案
  2. 确保您的配置中包含rerere.enabled=true
  3. 执行选项1(重做与更新后的母版的合并,请参阅问题)→现在rerere应该能够重用以前记录的分辨率
  4. (可选)再次取消设置rerere.enabled(可能有一些原因使其未启用,请参见Are there any downsides to enabling git rerere?

如果您不想使用该脚本,也可以手动进行培训,请参见https://stackoverflow.com/a/4155237/6309


更新

请记住,rerere仅记录冲突块(包含<<<<>>>>的冲突/解决方案)。对于同一文件的一个分支上的删除和另一分支上的修改而导致的冲突,它将不会记录解决方案。此外,它不会记录您在冲突请求之外进行的其他任何更改。

尽管它不是很流行,但是您还有另一种选择,尤其是如果origin/master已发布给不知名的人:在您的本地{ {1}}并强制推动。

我过去多次选择此选项,不一定来自相同的情况,但是在其他需要重写origin/master的情况下也是如此。如果您的团队很小,那就只是沟通/协调问题。