【问题标题】:Why does a seemingly possible merge using Git have conflicts?为什么使用 Git 看似可能的合并会发生冲突?
【发布时间】:2014-07-08 22:13:20
【问题描述】:

简而言之,为什么文件foo.txt 有内容

a
b

未能与foo.txt 具有内容的分支合并:

a

c

?

较长的版本是:为了试验 Git 和合并,我做了以下操作:

  1. mkdir 一个新目录和cd 进入它和git init
  2. 创建一个文件foo.txt并添加行a(第一次就是这样,第二次在a之后有2个空行)
  3. 提交它,现在git checkout -b feature 和git checkout -b sprint(据我所知,连续执行它而不是先切换回master 并创建sprint 没有区别,因为分支是基于 commitID 创建的,无论哪种情况,它们都完全相同。
  4. 现在git co feature 使文件看起来像a 然后空行然后c 在第三行
  5. 现在提交它,然后执行git checkout sprint 并使文件看起来像a,然后下一行是b。
  6. 现在提交它,现在做一个git merge feature

据推测,合并可能已经成功,与内容

a
b
c

但是为什么失败了?与其猜测“可能线条太接近”,是否可以从文档或参考中给出更明确的答案?

我还尝试在a 和b 之间以及b 和c 之间添加一个空行,因此它们之间的间距更大,但在foo.txt 的第一个版本中没有初始空行,结果是一样的:合并冲突。

【问题讨论】:

    标签: git


    【解决方案1】:

    Git 在行级别检查差异。因此,假设您的文件的第一个版本如下所示:

    a
    

    现在您在名为 feature 的分支上创建文件的第二个版本:

    a
    b
    

    在这个版本中,您更改了两行。为什么你认为是两条线?那么在a 的末尾添加了一个换行符\n。

    在sprint 分支中,您添加了另一个版本的文件:

    a
    
    c
    

    现在你修改了三行。

    如果您现在尝试合并这两个修改,git 会识别出您在两次提交中都更改了第 1 行和第 2 行,因此 git 不知道要采用哪个版本并发生冲突。

    【讨论】:

      【解决方案2】:

      正如你所说,它们离得太近了。让我们使用没有空行的共同祖先以避免混淆。如果你们有共同的祖先:

      line 1
      line 2
      line 3
      line 4
      

      然后你编辑两边:

      line 1
      LINE TWO
      line 3
      line 4
      

      还有:

      line 1
      line 2
      LINE THREE
      line 4
      

      那么 git diff/merge 引擎 (xdiff) 就会产生冲突。虽然我找不到这方面的文档,但显然可以凭经验看到。这是一个实现细节,虽然很常见。

      如果您将自动合并视为描述更改的区域,相对于其他区域进行描述(而不是行,由数字寻址),这可能更有意义:第一面在line 1 之后和line 3 之前更改数据。第二面在line 2之后和line 4之前更改数据。

      但是,当您尝试关联这些更改时,您会遇到麻烦:第一方删除了第二方用来描述其更改的上下文 (line 3)。

      只要有一些上下文(即更改不是“太接近”),这应该可以工作,即使该上下文是单行。如果您的共同祖先是:

      a
      
      
      
      d
      

      一方面是:

      a
      b
      
      
      d
      

      另一边是:

      a
      
      
      c
      d
      

      然后这将成功自动合并为:

      a
      b
      
      c
      d
      

      【讨论】:

      • 是的,我注意到如果b 和c 被换行符隔得更远,那么它们可以成功合并
      【解决方案3】:

      合并导致了冲突,因为您在每个分支上都以几乎相同的方式修改了文件。 Git 可以尝试自己解决冲突,但因为它做出的任何决定都可能是错误的,它会让你去做。

      Git 不会查看每一行的更改内容。只有一行被更改或添加。在一个分支中,您添加了一个新行,而在另一个分支中,您添加了一个字符和一个新行。在两个分支中,您都在第一个分支之后立即添加一行,而 git 希望您在合并时确定文件中的哪一行。

      您不会有冲突,因为 git 会在每个分支上看到文件中的独立更改。但是因为每个分支的同一行都发生了变化,所以 git 发生了冲突,请您解决。

      【讨论】:

      • 原始发帖人指出他的文件确实包含三行(a,后跟两个空格),这仍然是合并冲突。
      【解决方案4】:

      基本上对于 git,我相信每个具有不同历史的合并都是冲突。但它会尽量自己解决。它会尝试应用(使用git apply)从 diff 到目标分支的文件的每个更改,但是当应用失败时,它不会再做任何事情,它会让程序员解决它。

      在您的文件中,在分支feature 中,您已将a\n\n 更改为a\n\nc,在分支sprint 中您已将a\n\n 更改为a\nb\nc。 git 默认情况下空行和空格的变化很重要。它无法决定应用哪个更改,因为它们既不同又相互冲突。

      【讨论】:

        猜你喜欢
        • 2016-04-07
        • 1970-01-01
        • 2013-05-02
        • 2013-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多