Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git:关于合并算法、冲突格式以及与合并工具的相互作用的混淆_Git_Algorithm_File Format_Git Merge Conflict_Mergetool - Fatal编程技术网

Git:关于合并算法、冲突格式以及与合并工具的相互作用的混淆

Git:关于合并算法、冲突格式以及与合并工具的相互作用的混淆,git,algorithm,file-format,git-merge-conflict,mergetool,Git,Algorithm,File Format,Git Merge Conflict,Mergetool,我不知道细节,但据我所知,合并和冲突解决的过程如下(假设存储库中只有一个文件,在两个分支中修改): 用户发出git merge命令 Git应用一些特定于Git的算法来自动合并两个修改过的文件。为此,它创建文件的基本、本地、其他和备份版本 然后将合并结果写入原始跟踪文件(称之为合并) 假设存在冲突。Git使用某种格式来表示冲突(标记)。然后将其状态设置为“合并”或类似状态 如果用户随后发出git mergetool…将打开配置的外部合并工具,参数指向基本、本地、其他,当然还有合并 有几点我感到困惑

我不知道细节,但据我所知,合并和冲突解决的过程如下(假设存储库中只有一个文件,在两个分支中修改):

  • 用户发出
    git merge
    命令
  • Git应用一些特定于Git的算法来自动合并两个修改过的文件。为此,它创建文件的基本、本地、其他和备份版本
  • 然后将合并结果写入原始跟踪文件(称之为合并)
  • 假设存在冲突。Git使用某种格式来表示冲突(
    标记)。然后将其状态设置为“合并”或类似状态
  • 如果用户随后发出
    git mergetool…
    将打开配置的外部合并工具,参数指向基本、本地、其他,当然还有合并
  • 有几点我感到困惑:

    • 工具是否总是理解Git的冲突格式?标准化了吗?那么
      diff3
      选项呢?它是否也被外部工具普遍理解
    • 该工具是否会应用自己的合并算法,并将Git的输出全部丢弃
    • 当Git需要执行递归合并(因为有几个合并基)并且中间合并会产生冲突时,它会像对待任何其他非冲突文本一样将内部冲突标记视为纯文本吗?或者冲突格式本身是递归的

    我找不到任何能真正说明整个故事的解释。

    合并工具不会用冲突标记解析工作目录中的文件。他们读取祖先、我们的和他们的文件,这些文件是git mergetool从索引创建的,并放在磁盘上


    他们将使用自己的逻辑生成合并结果,并覆盖Git创建的文件。

    完整答案很复杂。爱德华·汤姆森的书涵盖了大部分内容。这里有相当多的细节

    不过,让我们从以下内容开始:
    git mergetool
    运行—我应该说,您运行it—在
    git merge
    的所有其余部分完成之后。在
    git merge
    完成之前(由于冲突而失败),您的合并工具甚至不会输入图片。这在很大程度上改变了你思考这些问题的方式

    (递归和解析)合并的工作原理 用户发出
    git merge
    命令

    到目前为止还不错

    Git应用一些特定于Git的算法来自动合并两个修改过的文件

    哎呀,不,我们已经出轨了,火车可能要下悬崖了。:-)

    此时的第一步是选择合并策略。让我们选择默认(
    -s recursive
    )策略。如果我们选择其他策略,下一步可能会有所不同(我们的-s与我们的完全不同,
    -s八达通的
    也有所不同,但现在这些都不有趣)

    下一步是查找所有合并基。幸运的话,只有一个。稍后我们将回到递归问题。不过,可能没有合并基础。较旧版本的Git使用空树作为伪合并基。较新版本2.9或更高版本要求您在此处添加
    ——允许不相关的历史记录
    (然后以相同的方式继续)。对于空树,在两个非基提交中都会添加每个文件

    如果有一个合并基,它可能与任一分支尖端相同。如果是,则没有要执行的合并。不过,这里也有两个子案例。可能没有要合并的内容,因为合并基础是另一个提交,而另一个提交位于当前提交的“后面”(是其祖先)。在这种情况下,Git总是什么都不做。或者,另一个提交可能在当前提交之前(其后代)。在这种情况下,Git通常执行快进操作,除非您指定
    --no ff
    。在这两种情况下(快速前进或
    --无ff
    ),不会发生实际合并。取而代之的是,进一步的前向提交被提取。它要么成为当前提交(快进合并:无论您在哪个分支上,它现在都指向前面的提交),要么Git使用该提交树进行新提交,新提交成为当前提交

    真正的合并:将一个合并基合并为两个提交 我们现在正处于这样一个阶段:一个合并基提交B,两个提交L(本地或左侧,
    --我们的
    )和R(远程或右侧,
    --他们的
    )。现在,两个正常的(
    -s recursive
    -s resolve
    )策略在启用重命名检测的情况下执行一对
    git diff--name status
    操作,以查看B-to-L更改中是否有文件更改了它们的名称,以及B-to-R更改中是否有文件更改了它们的名称。这还可以发现L或R中是否有新添加的文件,以及L或R中是否删除了文件。所有这些信息都被合并以生成文件标识,以便Git知道要合并哪些更改集。这里可能存在冲突:例如,一个文件的路径是基本的PB,但现在是PL和PR,它有一个重命名/重命名冲突

    在这一点上的任何冲突——我称之为高级冲突——都不在文件级合并的范围之内:它们将使Git以冲突结束这个合并过程,而不管发生什么。然而,与此同时,正如我上面所说,我们最终得到了“已识别的文件”,而没有对其进行定义。不严格地说,这意味着仅仅因为某个路径P被更改,并不意味着它是一个新文件。如果在基本提交B中有一个文件
    base
    ,现在它在L中被称为
    重命名
    ,但仍然被称为
    base
    
    $ ls $(git --exec-path)/mergetools
    
    setup_user_tool () {
            merge_tool_cmd=$(get_merge_tool_cmd "$tool")
            test -n "$merge_tool_cmd" || return 1
    
            diff_cmd () {
                    ( eval $merge_tool_cmd )
            }
    
            merge_cmd () {
                    ( eval $merge_tool_cmd )
            }
    }