【问题标题】:Why is a 3-way merge advantageous over a 2-way merge?为什么 3 路合并优于 2 路合并?
【发布时间】:2011-05-06 22:55:58
【问题描述】:

Wikipedia 表示 3 路合并比 2 路合并更不容易出错,而且通常不需要用户干预。为什么会这样?

一个 3 路合并成功而 2 路合并失败的示例会很有帮助。

【问题讨论】:

    标签: version-control merge conflict three-way-merge


    【解决方案1】:

    假设您和您的朋友都签出了一个文件,并对其进行了一些更改。您在开头删除了一行,而您的朋友在末尾添加了一行。然后他提交了他的文件,您需要将他的更改合并到您的副本中。

    如果您正在执行双向合并(换句话说,差异),该工具可以比较两个文件,并看到第一行和最后一行不同。但是它怎么知道如何处理这些差异呢?合并后的版本应该包括第一行吗?它应该包括最后一行吗?

    通过三向合并,它可以比较两个文件,但它也可以将每个文件与原始副本(在你们中的任何一个更改之前)进行比较。所以它可以看到您删除了第一行,而您的朋友添加了最后一行。它可以使用该信息来生成合并版本。

    【讨论】:

    • “但是它怎么知道如何处理这些差异呢?” 不明白。如果它已经可以看到两个文件之间的差异(不参考原始文件),为什么不能按照文件时间戳的递增顺序依次应用这两个更改?那就是:它从我朋友提交的副本开始,将其作为(新的)原始副本(在顶部添加行),然后在它之上应用我的本地更改(在底部删除行)。
    • @Harry 说原版有三行(ABC)。它从我朋友的副本 (ABCD) 开始,并将其与我的副本 (BC) 进行比较。没看原文,可能以为我把A和D都去掉了,最后的结果应该是BC。
    • @Harry 如果每个文件都有一个自共同祖先以来的时间戳更改列表,那么您将进行 3 路合并。您描述的方法需要将文件倒回到共同祖先,以便按时间顺序应用差异。换一种说法,我不确定“两个文件之间的时间戳差异没有参考共同祖先”是否有明确的含义。
    【解决方案2】:

    perforce 演示中的This slide 很有趣:

    三路合并工具的基本逻辑很简单:

    • 比较基础文件、源文件和目标文件
    • 识别源文件和目标文件文件中的“块”:
      • 与基数不匹配的块
      • 确实匹配基础的块
    • 然后,将包含以下内容的合并结果放在一起:
      • 所有 3 个文件中相互匹配的块
      • 与源或目标中的基础不匹配但两者都不匹配的块
      • 与基础不匹配但相互匹配的块(即,它们在源和目标中的更改方式相同)
      • 冲突块的占位符,由用户解决。

    请注意,此插图中的“块”纯粹是象征性的。每个都可以表示文件中的行,或层次结构中的节点,甚至是目录中的文件。这完全取决于特定的合并工具的能力。

    您可能会问,与 2 路合并相比,3 路合并有什么优势。实际上,没有双向合并之类的东西,只有区分两个文件并允许您通过从一个文件或另一个文件中选取块来“合并”的工具。
    只有三向合并提供您能够知道一个块是否是对原点的更改以及更改是否冲突。

    【讨论】:

    • "更改是否冲突。" - 2路合并(差异)是否也显示冲突(尽管信息在冲突来源时丢失)/
    • 然而,在 Git 中进行 4 路合并是很常见的,但基数实际上并不相同。仍然是 3 路合并更好,2 路。
    • @Wernight,有 5 路合并吗?
    • @Pacerier 我不知道,但这就是 git cherry-pick 或 rebase 期间实际发生的情况。
    • 非常详细有用的解释
    【解决方案3】:

    三向合并是在应用一个基本文件的两个变更集时合并它们,而不是应用一个,然后将结果与另一个合并。

    例如,在同一位置添加一行的两个更改可能被解释为两个添加,而不是一行的更改。

    例如,文件a被两个人修改,一个添加moose,一个添加mouse。

    #File a
        dog
        cat
    
    #diff b, a
        dog
    +++ mouse
        cat
    
    #diff c, a
        dog
    +++ moose
        cat
    

    现在,如果我们在应用变更集时合并它们,我们将得到(3 路合并)

    #diff b and c, a
        dog
    +++ mouse
    +++ moose
        cat
    

    但是如果我们应用 b,然后看看从 b 到 c 的变化,看起来我们只是将 'u' 更改为 'o'(双向合并)

        #diff b, c
        dog
    --- mouse
    +++ moose
        cat
    

    【讨论】:

      【解决方案4】:

      借鉴 AWS CodeCommit: 开发人员工具 > CodeCommit > 存储库 > RepositoryName > 拉取请求 > 拉取请求名称 > 合并

      【讨论】:

      • 图中哪一行是source branch,哪一行是designation branch?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-02
      • 2011-01-14
      • 2014-10-12
      • 1970-01-01
      • 2014-03-29
      • 2022-01-25
      相关资源
      最近更新 更多