第二次尝试从分支机构合并到主机的Git冲突

时间:2017-05-27 02:39:05

标签: git merge git-merge git-merge-conflict

考虑以下git网络和流程:

feature-foo        _._._2_._._
                  /           \
master      __1__/__._.3____._._\___4__5_________7_  (now: 1.1.0-SNAPSHOT)
                        \         
release-1.0.x            \___.__._._.__6__._._.____  (now: 1.0.1-SNAPSHOT)

随着时间的推移采取以下行动:

  1. master的版本提升为1.0.0-SNAPSHOT
  2. A.java分支
  3. 中删除feature-foo
  4. 分支release-1.0.x,将master的版本提升至1.1.0-SNAPSHOT以进行下一次发布开发
  5. B.java仅在B'.java
  6. 上修改为master
  7. 手动将release-1.0.x合并回mastergit merge而不是通过GitLab MR)
  8. release-1.0.x的版本提升至1.0.0并对其进行标记,然后再次将其翻到1.0.1-SNAPSHOT
  9. 第二次尝试将release-1.0.xmaster合并回发布分支的最新更改
    • 36是通过/tmp上的bash脚本完成的git clone
    • 57是在具有完整/path/to/tmp
    • 的单独git clone上手动完成的
    • feature-foo被合并回主人(接受MR)
    • 来自master
    • 1A.java
    • release-1.0.x仍有A.java(很好)
    • release-1.0.x仍有B.java(很好)
    • 某些文件已合并回5 ,不包括 A.javaB.java

    对于步骤57,我做了

    git clone ...
    git checkout release-1.0.x
    git checkout master
    git merge --no-ff --no-commit release-1.0.x
    
    successfully on 5:
    
    git add .
    git commit
    git push
    

    奇怪的是,现在第二次尝试,我遇到了大量的冲突,包括两者 A.java(它试图将其带到主人身上)和B.java(它试图将过时的发布分支合并到主分支中并产生冲突)。

    我的问题是:

    • 我在这里遗漏了一些东西吗?
    • 将长实时发布分支合并到主服务器(例如每月两次)的过程是否正确?
    • 为什么我现在发生冲突而不是第一次尝试?

    修改

    pom.xml内的版本已被添加到.gitattributes,以便使用我们的策略进行处理。

2 个答案:

答案 0 :(得分:1)

这真的应该是一个评论,但我没有足够的空间,也不能很好地格式化。

您绘制的提交图只有一个合并基础,用于您标记为7的两个提交,并且可能未标记为全部(release-1.0.x的提示提交)。合并基础提交是您标记为3的提交。但在你的文字中,你说:

  

某些文件已合并回5 ...

然而,在任何地方都没有连接5的额外图表行:5看起来像普通的非合并提交,其(单个)父项是提交4。因此,我不确定您是否过度简化了图表。

最简单的方法是让Git告诉你当你的合并有问题时, Git 认为合并基础是什么。如果您当前在分支master并且即将运行git merge release-1.0.x,您可以使用以下命令查看Git认为哪些提交是合并基础(可能是复数):

git merge-base --all HEAD release-1.0.x

输出是一些提交哈希ID - 幸运的是,只有一个 ID - 这是合并基础。 (如果您已经进行了合并,那么在合并之前提交 当前提交时,将HEAD替换为哈希ID。同样,如果release-1.0 .x自合并以来已移动,将其替换为合并的提交的哈希ID。)

如果有多个合并库,则会遇到一些问题。使用-s recursive合并策略的Git默认是合并基础。此合并的结果是一个新的“虚拟提交”,然后将其视为最终合并的合并基础。当你可以(递归地)执行我将要手动描述的内容时,它会非常痛苦:除了其他事项,您可能必须为每个潜在的虚拟提交进行实际提交。但幸运的是, 1 只有一个合并基础,也许毕竟提交3

无论如何:

  

我遇到了大量的冲突,包括A.javaB.java ......

要查看合并将执行的操作,以及为什么它认为要为这两个文件合并的内容,请运行:

git diff -M <merge-base-commit> <tip-1> > /tmp/merge-input-1
git diff -M <merge-base-commit> <tip-2> > /tmp/merge-input-2

此处 tip-1 master tip-2 release-1.0.x。合并基础提交当然是您在上面找到的(单个)哈希ID。

如果所有三个提交中都存在两个有问题的文件,那么你不会遇到任何重命名问题,所以我甚至不会把它们带到这里。

1 嗯,从技术上讲,这不是运气问题。只有在进行十字交叉合并时才会出现合并基础模糊,即使这样,它们也需要具有相同的“距离”。因此,生成多个合并基础相对困难。

最后,还有最后一点。它最终可能很重要,但实际上这不是问题。它认为:

  

pom.xml内的版本已被添加到.gitattributes,以便使用我们的策略进行处理。

无法在.gitattributes中获得真正的“我们的”策略。 (甚至没有“我们的”标记。)我在这里猜你的意思是你写了一个合并驱动程序,当有一个<{1>} 时,它实际上使用了git checkout --ours 冲突。您也可能编写了一个在三个输入上使用git merge-file --ours的合并驱动程序。

这些都略有不同。

首先要知道的是,如果Git发现冲突,您的合并驱动程序运行。

当您执行上述两个git diff -M命令时,您可以看到哪些文件包含需要组合的更改。如果,与合并基础 B 相比,两个分支提示都有一个不同的 pom.xml,那么就有一些东西需要合并。也就是说,假设在diff#1中我们看到:

-this
+that

在差异#2中我们看到:

-another
+another

这些需要组合,因此Git将调用您的合并驱动程序。 (更准确地说,Git会检查三个哈希ID:基本文件的哈希值,提示#1中的文件哈希值以及提示#2中的文件哈希值。如果所有三个不同,Git将调用您的合并驱动程序。 )

另一方面,也许只有#1提示或只有#2提示更改文件(因此它在底座中与在另一个提示中相同)。在这种情况下,Git会选择一个更改过的文件,而不运行驱动程序。对于像pom.xml这样的文件,这通常可能就是你想要的! (对于版本编号,它可能不是你想要的,但也许你有另一个步骤来处理它。)

如果Git 调用你的驱动程序,那么它当然取决于你的驱动程序。这就是“保持我们的”与“git merge-file --ours”不同的地方。前者更像是-s ours策略:它完全忽略了base和other / theirs文件。后者使用“同时进行两项更改,但如果发生冲突,请使用我们的解决方案方法,并且类似于-X ours扩展策略选项。

答案 1 :(得分:0)

6岁之后,主人和发行版都碰到了他们的版本。你没有确切地提到碰撞版本的含义,但是我假设同一文件中的相同行被编辑到两个分支中,这将导致冲突。至于为什么a.java和b.java突然发生冲突,我的猜测是他们(或他们的路径)是在6日编辑的。