19

在它出现之前,我已经查看了关于这个主题的几个线程,包括这些:

我正在考虑为我们的开发组切换到 Mercurial(来自 Subversion)。在我这样做之前,我正在做通常的优点/缺点列表。

我的“优点”之一是合并在 Mercurial 中更胜一筹,但到目前为止,我还没有找到令人信服的证据。也就是说,在 HgInit.com 上发表了我无法验证的声明:

例如,如果我稍微改变一个函数,然后将它移动到其他地方,Subversion 并不会真正记住这些步骤,所以当需要合并时,它可能会认为一个新函数突然出现. 而 Mercurial 会分别记住这些内容:函数更改,函数移动,这意味着如果您也稍微更改了该函数,Mercurial 更有可能成功合并我们的更改。

这将是非常引人注目的功能,但据我所知,这只是热空气。我一直无法验证上述说法。

我创建了一个 Mercurial 存储库,做了一个 Hello World,然后克隆了它。在其中,我修改了函数,提交它,然后移动它,然后提交它。在另一个中,我只是在函数中添加了另一个输出行并提交。

当我合并时,我得到的合并冲突与使用 Subversion 时基本相同。

我知道 mercurial 可以更好地跟踪文件重命名,并且 DVCS 除了合并之外还有其他优势,但我对这个例子很感兴趣。乔尔·斯波尔斯基(Joel Spolsky)是不是在这里偏离基地,还是我错过了什么?

我在这方面没有经验,但似乎因为 Mercurial 保留了更多信息,理论上它可以在合并方面做得更好(如果开发人员也经常签入)。例如,我认为 Mercurial 通过比较多个更改来获取上下文更改是可行的,例如,我修改函数、签入、移动函数、签入,然后 Mercurial 将这两个部分关联起来。

然而,Mercurial 的合并似乎并没有真正利用添加的信息,并且似乎与 Subversion 的操作方式相同。它是否正确?

4

3 回答 3

6

据我所知,任何说 Mercurial 以小于文件大小的块跟踪移动代码的人都是错误的。它确实独立于代码更改跟踪文件重命名,因此如果 Dave 重命名文件并且 Helen 更改了文件中的某些内容,它可以自动合并,但据我所知,Subversion 也可以这样做!(CVS 不能。)

但是有一种方法可以让 Mercurial 的合并逻辑比 Subversion 的好得多:它可以记住冲突解决方案。考虑这个历史图表:

base ---> HELEN1 ---> merge1 --> HELEN2 -> merge2
     \--> DAVE1 ---/                    /
                   \--> DAVE2 ---------/

Helen 和 Dave 独立进行了更改。Helen 拉出 Dave 的树并合并,然后在此基础上进行了另一项更改。与此同时,戴夫继续编码,没有费心从海伦那里拉出来。然后海伦又拉了戴夫的树。(也许 Dave 正在开发主要的开发主干,而 Helen 正在开发一个功能分支,但她想定期与主干更改同步。)在构建“merge2”时,Mercurial 会记住在“merge1”中完成的所有冲突解决方案并且只显示 Helen新的冲突,但 Subversion 会让 Helen 从头开始​​重新进行合并。(有一些方法可以避免使用 Subversion 执行此操作,但它们都涉及额外的手动步骤。Mercurial 会为您处理。)

有关更多信息,请阅读为 Monotone 开发的标记合并算法,AFAIK 现在已被 Mercurial 和 Git 使用。

于 2011-02-12T23:20:50.500 回答
1

AFAIK,SVN 在内部进行所有合并 - 合并工具仅适用于存在冲突的情况,因为(显然)它需要告诉您并让您修复它。

不冲突的情况是基于应用补丁 - 即,svn 将采用您在修订中所做的更改,并将这些更改应用于目标。SVN 的最新版本(从 1.5 开始)会记住您之前所做的合并,将此信息存储在与目录关联的属性中。与 1.5 相比,1.6 在处理这些属性方面做得更好。

SVN 不会通过比较 2 棵树并对其进行比较来合并 -请参阅本书- 除非要合并的树不相关,否则它才会执行 diff-type 合并操作(或者您指定 --ignore-ancestry 选项) . 这是一个简短的描述发生的事情。当你合并过去的冲突时,你可以看到这一点——一旦你解决了一个棘手的修订合并,svn 会记住哪些修订被合并,并将再次应用这些更改。您可以通过尝试来证明这一点 - 分支、编辑 2 个文件、合并以产生冲突。仅在同一行编辑分支文件,然后合并 - 即使目标文件没有更改,它也会弹出冲突,但因为合并正在将更改应用于已更改的行,而该行已从分支文件预期的内容更改(即就像补丁一样,它显示了它认为将要更改的行应该是什么)。在实践中,您不会看到这一点,因为您不会反复拒绝合并更改。

但是,SVN 在重命名文件方面做得很差,因为它将它们跟踪为删除+添加操作。其他 SCM 做得更好 - 但即使它们也无法真正判断文件是否被重命名,或者被删除和添加,尤其是当该文件也被修改时。Git 使用一些启发式方法来尝试确定这一点,但我看不出它保证成功。在我们有一个挂钩到文件系统的 SCM 之前,我认为情况仍然如此。

于 2011-02-14T18:03:04.370 回答
1

两件事情:

  1. Mercurial 确实有内部代码来进行合并,如果内部“预合并”失败,它只会调用外部合并工具。

    您链接到HG Book,它说没有用于处理冲突的内置工具(与没有内置合并不同)和Mercurial wiki,其中声明 Mercurial 将在调用外部之前尝试在内部进行合并程式。

  2. 您链接到一个问题,我的回答给出了一个明确的案例,即 Mercurials 成功而 Subversion 在合并中失败。这是使用 Mercurial 和 Subversion 中的内部合并代码的开箱即用比较。

于 2011-02-22T13:58:04.277 回答