本文介绍了导致git合并冲突的原因和案例是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述




    必要和充分的条件,和/或

    所有案件或一些常见案件 >可能会导致 code>,如果使用 path / to / foo.txt 。显然,这个文件在整个合并过程中都是同一个文件,所以Git将三个路径标识为一个文件。
    或者,可能有多达三种不同的路径,

    path / to / basename , P path2 / to2 / left 和 R path3 / to3 / right 。其中一个或多个甚至可能不存在。这些结果是:如果P 和 P = P ;如果 P 等于左侧或右侧路径中的一个,但另一个不存在,则重命名/删除冲突;或重命名冲突,如果

    b

    $ b

    如果还没有高级冲突(添加/添加,重命名/重命名或重命名/删除),则可能仍有重命名/修改或重命名/删除冲突,只要由两个或三个路径名称命名的斑点(文件内容)的散列ID不匹配即可。



    所有这些高级别冲突会导致合并冲突,但本身不会导致任何冲突标记。为了达到这个目的,我们现在必须实际上将基础文件与两个侧面文件合并(这意味着所有三个文件都必须存在,或者对于添加/添加的情况,我们将一个小文件作为基础版本)。



    这种合并可能会或可能不会有自己的冲突。如果合并增加了低级别冲突,我们将得到冲突标记。如果没有高级冲突(所有三个提交中的路径都是相同的),但需要完全合并(哈希全部不同),我们可能会与冲突标记发生低级冲突。



    Git在文件冲突中需要什么



    为了在工作树中的一个文件中获得合并冲突,Git必须看到同一行由左侧和右侧版本更改,但以不同方式更改 。 (请记住,所有三个散列必须有所不同,以便Git将一组实际变化组合为 diff P P

    最显而易见和最不容易混淆的情况



    最明显的情况发生在一边(先让我们选择左边)说:

     不变的上下文
    - 变动的线
    +替换1
    更多不变的上下文

    另一个说:

     不变的上下文
    -changed线
    +替换2
    更多不变的上下文

    这里删除了一行或多行,代替插入一行或多行,但插入的行不匹配。在这种情况下,合并冲突风格表示为:

     不变的上下文
    <<<<<<左标签
    替换1
    =======
    替换2
    >>>>>>>右标签
    更多不变的上下文

    diff3 context风格将其呈现为:

     不变的上下文
    <<<<<<<<<<<<<<<<<<替换1
    |||||||合并后的共同祖先
    变换行
    =======
    替换2
    >>>>>>>右标签
    更多不变上下文

    如果我们仅添加文本,但添加不同的文本,在同一行中,我们也会遇到合并冲突。同样,每一边添加的文字都显示在冲突标记中。 (如果我们将相同的文本添加到双方中,无论是作为新文本还是作为替换文本替换文本,Git都会获取此添加的一个副本,并且没有冲突。)



    有些令人困惑的情况



    如果替换 em>行是空的 - 即,如果左侧或右侧diff读取:

     不变的上下文
    - 更改行
    更多不变的上下文

    然后一个但不是两个 合并或 diff3 样式标记文件中的替换行缺失。 (如果两个diff都只是删除原来的行,那就没有冲突了:Git需要删除一个)



    同样,如果一边添加了 a在对方删除的行的上方或下方,会发生冲突。这一次冲突显示保留后添加a的一侧具有所有行,而其他另一侧没有行。例如:

     一些合并冲突。 
    会冲突的行。
    +在其下面添加行
    其余的

    vs:

     一些合并冲突。 
    - 会冲突。
    其余的

    (如果添加上面的行而不是下面的行)。



    这是 diff3 冲突风格非常有用的地方。以下是这些案例中的整个合并文件:

     我们需要一个基本文件
    ,其中
    一些合并冲突。
    <<<<<< HEAD
    |||||||合并共同祖先
    会冲突的行。
    =======
    更改会冲突的行。
    >>>>>>> b2

    合并冲突示例的
    基本文件的其余部分。

    请注意,现在很明显 - 或者至少不那么神秘 - 有一行读取 Line,它会冲突。在基本版本中,我完全从左侧删除 HEAD 版本,并在右侧替换为不同的行 b2 版本。


      What are

        the necessary and sufficient conditions, and/or

        all the cases or some common cases

      that can cause git merge report merge conflict?

      How does git merge determine whether a line or some lines containmerge conflict(s)?

      For example, I sometimes see cases like the following, where eitherPart 1 or Part 2 is empty in

      <<<<<<< HEAD
      (Part 1)
      =======
      (Part 2)
      >>>>>>> some-other-branch
      

      It looks unlikely to have a merge conflict to me. So what are some possible reasons thatcases like that have merge conflicts?

      Comparing the merge conflicts reported by git merge and thedifferences reported by git diff, is it correct that

        the differences reported by git diff might not necessarily be in the places of the merge conflicts reported by git merge, and

        the merge conflicts reported by git merge might not necessarily be in the places of the differences reported by gitdiff?

    Thanks.

    解决方案

    There are multiple parts to a complete, correct answer. First, we have to get to a normal three way merge in the first place (which in Git requires using -s recursive or -s resolve, and if using -s recursive, finding a single merge base and two other commits). You may, however, want to skip right down to the third section.

    The elements required for a normal three-way merge

    To do any merge at all, you need:

      a merge base commit B,a current commit L (left side, aka HEAD) that has B as an ancestor,another commit R that also has B as an ancestor.

    Since "is ancestor" allows node equality in the commit graph (technically it's a predecessor-or-equal ≼ comparison), it's possible to have B = L and/or B = R. If this is the case, however, then no merging is ever required, and if you do force a merge (using git merge --no-ff—this implies B = L and L ≺ R; the two unforced cases are "fast forward" not-actually-a-merge and a "nothing to merge" error) there will be no merge conflicts. So we may as well assume that the merge base precedes both sides of the merge.


    Using --allow-unrelated-histories, you can have Git substitute in the empty tree for an actual base commit, if L and R have no lowest common ancestor nodes. This, however, causes all identified files to be add/add conflicts.


    Given a merge, the elements required for a conflict

    Next, to get a conflict in some file path, you need either what I call a "high level" conflict or a "low level" conflict (or both). For this to occur, Git must identify (i.e., match together) files in B, L, and R. Due to the ability to add new files, rename files, and delete files, this does not require that the file have the same name in all three commits. In particular:

      If path P exists in all three of B, L, and R, the three files with path P are identified together. (That is, there's a path P, such as path/to/foo.txt, that has a matching P path/to/foo.txt and P path/to/foo.txt. Obviously this file is "the same file" all throughout the merge, so Git identifies the three paths as one file.)Or, there may be up to three different paths, P path/to/basename, P path2/to2/left, and P path3/to3/right. One or more of these may not even exist. These result in: add/add conflict, if ∄ P and P = P; a rename/delete conflict, if P equals one of the left or right paths, but the other does not exist; or a rename/rename conflict, if P ≠ P ≠ P.

    If there is not already a high level conflict (add/add, rename/rename, or rename/delete), there may still be a rename/modify or rename/delete conflict, as long as the hash IDs of the blobs (file contents) named by the two or three path names do not match.

    All of these "high level" conflicts cause a merge conflict, but do not by themselves result in any conflict markers. To get that, we must now actually merge the base file with the two side files (which means all three files must exist, or for the add/add case, we take a trivial empty file as the base version).

    This merge may or may not have its own conflicts. If the merge adds low level conflicts, we will get conflict markers. If there is no high level conflict (the path is the same in all three commits) but a full merge is required (the hashes all differ), we may get a low level conflict with conflict markers.

    What Git requires for a conflict within a file

    To get a merge conflict within one file in the work-tree, Git must see the same line changed by both left and right side versions, but changed in different ways. (Remember, all three hashes must differ, so that Git is combining a set of changes from, in effect, diff P P with those from diff P P.)

    The most obvious and least confusing cases

    The most obvious case occurs for one side (let's choose the left side first) to say:

     unchanged context
    -changed line
    +replacement 1
     more unchanged context
    

    and the other to say:

     unchanged context
    -changed line
    +replacement 2
     more unchanged context
    

    Here one or more lines are deleted and in their stead, one or more lines are inserted, but the inserted lines do not match. In this case the merge conflict style presents this as:

    unchanged context
    <<<<<<< left-label
    replacement 1
    =======
    replacement 2
    >>>>>>> right-label
    more unchanged context
    

    The diff3 context style presents this instead as:

    unchanged context
    <<<<<<< left-label
    replacement 1
    ||||||| merged common ancestors
    changed line
    =======
    replacement 2
    >>>>>>> right-label
    more unchanged context
    

    If we merely add text, but add different text, at the same line, we also get a merge conflict. Again, the added text from each side shows up in the conflict markers. (If we add the same text to both sides—either as new text, or as replacement text for a changed line, Git takes one copy of this addition and there is no conflict.)

    The somewhat confusing cases

    If one but not both of the replacement lines is empty—i.e., if the left or right side diff reads:

     unchanged context
    -changed line
     more unchanged context
    

    then one but not both of the replacement lines in the merge or diff3 style marked-up file is missing. (If both diffs simply delete the original lines, there is no conflict: Git takes one deletion.)

    Similarly, if one side adds a line above or below a line that the other side deletes, you get a conflict. This time the conflict shows that the side that retained-and-then-added a has all the lines, and other other side has no lines. For instance:

     some merge conflict.
     Line that will conflict.
    +add line below it
     Rest of the
    

    vs:

     some merge conflict.
    -Line that will conflict.
     Rest of the
    

    (and the same occurs if you add the line above instead of below).

    This is where the diff3 conflict style is very helpful. Here's the entire merged file for the one of these cases:

    We need a base file
    in which to make
    some merge conflict.
    <<<<<<< HEAD
    ||||||| merged common ancestors
    Line that will conflict.
    =======
    Change the line that will conflict.
    >>>>>>> b2
    Rest of the
    base file for the
    merge conflict example.
    

    Note that it's now obvious—or at least, less mysterious—that there was a line that read Line that will conflict. in the base version, which I deleted entirely from the left side HEAD version and replaced with a different line in the right side b2 version.

    这篇关于导致git合并冲突的原因和案例是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 20:05