【问题标题】:What makes some version control systems better at merging?是什么让一些版本控制系统更擅长合并?
【发布时间】:2010-10-02 08:57:32
【问题描述】:

我听说许多分布式 VCS(git、mercurial 等)比 Subversion 等传统 VCS 更擅长合并。这是什么意思?他们做了哪些事情来让合并变得更好?这些事情可以在传统的 VCS 中完成吗?

额外问题:SVN 1.5 的合并跟踪是否完全符合竞争环境?

【问题讨论】:

标签: svn git version-control mercurial merge


【解决方案1】:

SVN 的合并能力不错,简单的合并场景运行良好 - 例如发布分支和主干,主干跟踪 RB 上的提交。

更复杂的场景会很快变得复杂。例如,让我们从一个稳定的分支 (stable) 和trunk开始。

您想演示一个新功能,并希望基于stable,因为它比trunk 更稳定,但您希望所有提交也传播到trunk,而其余开发人员仍在 stable 上修复东西并在 trunk 上开发东西。

所以你创建了一个demo 分支,合并图如下:

  • stable -> demo -> trunk(你)
  • stable -> trunk(其他开发者)

但是,当您将更改从stable 合并到demo,然后将demo 合并到trunk,而其他开发人员也一直将stable 合并到trunk 时会发生什么? SVN 对 stable 的合并感到困惑,它被两次合并到 trunk

有一些方法可以解决这个问题,但是对于 git/Bazaar/Mercurial,这根本不会发生 - 他们意识到提交是否已经被合并,因为他们在合并路径上标识了每个提交。

【讨论】:

    【解决方案2】:

    大多数答案似乎都是关于 Subversion,所以这里有一个关于 Git(和其他 DVCS)的答案。

    在分布式版本控制系统中,当您将一个分支合并到另一个分支时,您会创建新的合并提交,它会记住您如何解决合并,并记住合并的所有父项。在 1.5 版之前的 Subversion 中根本就缺少这些信息;为此,您必须使用其他工具,例如 SVK 或 svnmerge。在进行重复合并时,此信息非常重要。

    借助这些信息,分布式版本控制系统 (DVCS) 可以自动为任意两个分支找到共同祖先(或共同祖先),也称为合并基础。看看下面的 ASCII-art 修订图(我希望它没有被弄得太糟糕),

    ---O---*---*----M---*---*---1 \ / \ - -* - -A2

    如果我们想要将分支“2”合并到分​​支“1”,我们想要用来生成合并的共同祖先将是标记为“A”的版本(提交)。但是,如果版本控制系统没有记录有关合并父级的信息(“M”是相同分支的先前合并),它将无法找到提交“A”,它会找到提交“O”而是作为共同祖先(合并基础)...这将重复已经包含的更改并导致大的合并冲突。

    分布式版本控制系统必须从一开始就做对,即他们必须使合并非常容易(无需标记/标记合并父级,并手动提供合并信息),因为获得其他人的方式将代码放入项目不是授予他/她提交访问权限,而是从他/她的存储库中提取:从另一个存储库获取提交并执行合并。

    您可以在 Subversion 1.5 中找到有关合并的信息。在Subversion 1.5 Release Notes。注意问题:您需要不同 (!) 选项将分支合并到主干,而不是将主干合并到分支,也就是。并非所有分支都是平等的(在分布式版本控制系统中,它们[通常]在技术上是等效的)。

    【讨论】:

      【解决方案3】:

      1.5 中的合并跟踪比没有合并跟踪要好,但它仍然是一个非常手动的过程。我确实喜欢它记录哪些 rev 已合并和未合并的方式,但它远非完美。

      Merge 在 1.5 中有一个不错的对话框。您可以选择要单独合并的修订版或整个分支。然后,您触发在本地发生的合并(并且永远持续),然后为您提供一堆文件供您阅读。您需要从逻辑上检查每个文件的行为是否正确(最好通过对文件进行单元测试),如果有冲突,则必须解决它们。一旦您感到高兴,您就可以提交您的更改,此时该分支被视为合并。

      如果你是零碎的,SVN会记住你之前说的你已经合并了,允许你合并。我发现一些合并的过程和结果至少可以说很奇怪......

      【讨论】:

        【解决方案4】:

        这些版本控制系统可以做得更好,因为它们有更多的信息。

        1.5 之前的 SVN 以及最新一代之前的大多数 VCS,实际上并不记得您在任何地方合并了两个提交。它记得这两个分支在第一次分支时共享一个共同的祖先,但它不知道任何可以用作共同点的最近合并。

        我对 SVN 1.5 后一无所知,所以也许他们对此有所改进。

        【讨论】:

        • 查看revctrl.org/CategoryMergeAlgorithm 以了解合并算法的一些(粗略)描述。其中一些算法复杂地使用了 SVN 根本不保留的有向无环图历史。不要忘记合并/重命名目录树/。
        【解决方案5】:

        轻率的回答:为什么有些编程语言在文本/数学方面比其他语言更好?

        真正的答案:因为他们必须如此。分布式 VCS 进行大部分合并时,冲突代码的作者都无法手动调整合并,因为合并是由第三方完成的。因此,合并工具必须在大多数情况下正确处理。

        在与 SVN 的合同中,如果你最终合并了一些你没有写过一侧或另一侧的东西,那么你就是在做一些时髦的事情(而且是错误的?)。

        IIRC 大多数 VCS 可以根据您要求他们使用的任何内容进行合并,因此(理论上)没有什么可以阻止 SVN 使用 GIT/mercurial 合并引擎。 YMMV

        【讨论】:

        • 也许我应该问如何他们更好,而不是为什么。关于外包合并的有趣点。
        • 太傻了,所有版本控制系统都有这个问题。使用 SVN,它总是在签入时间。您有一些更改想要签入并 - 惊喜!- 有人已经提交了相互冲突的更改。您必须同时提交您的更改,并将它们的更改合并为一个提交。
        • @Peter Burns:使用 SVN,您几乎总是有一位作者在进行合并。使用 Git/Hg/etc,合并可能由任何一方都没有编写的人完成。我将进行编辑以使其更清晰。
        • 我仍然不同意你的新帖子。唯一一次在 git 等人中完成合并。是当您明确合并两个不同的树时。诚然,SVN 会强制作者在提交之前进行合并,但如果您在 SVN 中使用分支,那么您同样有可能由第三方完成合并。
        • 好的,我显然在强调我的观点,所以这是我要发表的最后一条评论。第三方合并两个其他人的代码通常是个坏主意,分布式 VCS 不需要这样做。我已经使用 git 一年了,但我从来不需要将其他两个人的代码合并在一起,我也没有见过这个。
        猜你喜欢
        • 1970-01-01
        • 2010-11-22
        • 2011-03-04
        • 2012-03-04
        • 1970-01-01
        • 2011-03-17
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        相关资源
        最近更新 更多