在出现之前,我已经查看了有关此主题的多个线程,包括:
我正在考虑为我们的开发小组切换到 Mercurial(从 Subversion)。在这样做之前,我会列出通常的优点/缺点列表。
我的“优点”之一是 Mercurial 中的合并效果更好,但到目前为止我还没有找到令人信服的证据来证明这一点。也就是说,HgInit.com 上有一个我无法验证的声明:
例如,如果我稍微更改一个函数,然后将其移到其他地方,Subversion 并不真正记住这些步骤,因此当需要合并时,它可能会认为刚刚出现了一个新函数的蓝色。而 Mercurial 会分别记住这些事情:函数更改、函数移动,这意味着如果您也稍微更改该函数,Mercurial 更有可能成功合并我们的更改。
这将是一个非常引人注目的功能,但据我所知,这只是空话。上述说法我无法核实。
我创建了一个 Mercurial 存储库,做了一个 Hello World,然后克隆了它。在其中一项中,我修改了该函数,提交了它,然后移动了它,然后提交了它。在另一个中,我只是在函数中添加了另一个输出行并提交。
当我合并时,我遇到的合并冲突与使用 Subversion 时遇到的合并冲突基本相同。
我知道 Mercurial 可以更好地跟踪文件重命名并且还有其他除了合并之外,DVCS 还有其他优点,但我对这个示例很感兴趣。乔尔·斯波尔斯基 (Joel Spolsky) 是不是偏离了基地,还是我错过了什么?
我在这方面没有经验,但似乎由于 Mercurial 保留了更多信息,理论上它可以在合并方面做得更好(如果开发人员也经常进行签入)。例如,我认为 Mercurial 通过比较多个更改来获取上下文更改是可行的,例如,我修改函数、签入、移动函数、签入,然后 Mercurial 将这两个部分关联起来。
然而,Mercurial 的合并似乎并没有真正利用添加的信息,并且似乎与 Subversion 的操作方式相同。这是正确的吗?
Before it comes up, I've already looked at several threads on this topic, including these:
I'm looking at switching to Mercurial (from Subversion) for our development group. Before I do so I'm doing the usual pros / cons list.
One of my "pros" is that merging is superior in Mercurial, but so far I'm failing to find compelling evidence of that. Namely, there is a statement made on HgInit.com that I've been unable to verify:
For example, if I change a function a little bit, and then move it somewhere else, Subversion doesn’t really remember those steps, so when it comes time to merge, it might think that a new function just showed up out of the blue. Whereas Mercurial will remember those things separately: function changed, function moved, which means that if you also changed that function a little bit, it is much more likely that Mercurial will successfully merge our changes.
This would be extremely compelling functionality, but as far as I can tell, it's just hot air. I've been unable to verify the above statement.
I created a Mercurial repository, did a Hello World and then cloned it. In one I modified the function, committed it and then moved it, and then committed it. In the other I simply added another output line in the function and committed.
When I merge, I get basically the same merge conflict I would get using Subversion.
I get that mercurial can track file renames better and that there are other advantages to DVCS besides merging, but I'm interested in this example. Is Joel Spolsky off-base here, or am I missing something?
I'm not experienced in this area, but it does seem like since Mercurial keeps more information that it could, in theory, do better at merging (if developers also did frequent checkins). For example, I see it as feasible for Mercurial to get contextual changes from comparing multiple changes, e.g., I modify a function, check in, move the function, check in, and Mercurial associates those two pieces.
However, Mercurial's merging doesn't seem to actually take advantage of the added information, and appears to be operate the same way as Subversion. Is this correct?
发布评论
评论(3)
据我所知,任何说 Mercurial 以小于文件大小的块跟踪移动代码的人都是错误的。它独立于代码更改跟踪文件重命名,因此如果 Dave 重命名文件并且 Helen 更改文件中的某些内容,它可以自动合并,但据我所知,Subversion 也可以做到这一点! (CVS 不能。)
但是 Mercurial 的合并逻辑在某种程度上比 Subversion 的要好得多:它会记住冲突解决方案。考虑这个历史图表:
Helen 和 Dave 独立进行了更改。海伦拉了戴夫的树并合并,然后在此基础上做了另一个改变。与此同时,戴夫继续编码,没有费心从海伦那里拉出来。然后海伦又拉了戴夫的树。 (也许 Dave 正在开发主干,而 Helen 正在开发一个功能分支,但她想定期与主干更改同步。)构建“merge2”时,Mercurial 会记住“merge1”中完成的所有冲突解决方案并且只显示 Helen new 冲突,但 Subversion 会让 Helen 从头开始重新进行合并。 (您可以通过多种方法避免使用 Subversion 执行此操作,但它们都涉及额外的手动步骤。Mercurial 会为您处理。)
有关详细信息,请阅读 标记合并算法是为 Monotone 和 AFAIK 开发的,现在 Mercurial 和 Git 都在使用。
As far as I know, anyone who says Mercurial tracks moving code around in less than file-sized chunks is just wrong. It does track file renames independently from code changes, so if Dave renames a file and Helen changes something in the file, it can automerge that, but as far as I know, Subversion can do that too! (CVS can't.)
But there is a way in which Mercurial's merge logic is dramatically better than Subversion's: it remembers conflict resolutions. Consider this history graph:
Helen and Dave made changes independently. Helen pulled Dave's tree and merged, then made another change on top of that. Meantime, Dave went on coding without bothering to pull from Helen. Then Helen pulled Dave's tree again. (Maybe Dave is working on the main development trunk, and Helen's off on a feature branch, but she wants to sync up with trunk changes periodically.) When constructing "merge2", Mercurial would remember all of the conflict resolutions done in "merge1" and only show Helen new conflicts, but Subversion would make Helen do the merge all over again from scratch. (There are ways you can avoid having to do that with Subversion, but they all involve extra manual steps. Mercurial handles it for you.)
For more information, read about the mark-merge algorithm which was developed for Monotone and AFAIK is now used by both Mercurial and Git.
AFAIK,SVN 在内部完成所有合并 - 合并工具仅适用于存在冲突的情况,因为(显然)它需要告诉您相关信息并让您修复它。
非冲突情况基于应用补丁 - 即,svn 将采用您在修订版中所做的更改,并将这些更改应用到目标。 SVN 的最新版本(自 1.5 起)会记住您之前进行的合并,并将此信息存储在与目录关联的属性中。与 1.5 相比,1.6 在处理这些属性方面做得更好。
SVN 不会通过比较两棵树并比较它们来合并 - 参见本书 - 除非要合并的树不相关,否则它才会执行 diff 类型的合并操作(或者您指定 --ignore -血统选项)。 这是所发生情况的简要描述。
当您合并过去的冲突时,您可以看到这一点 - 一旦您解决了棘手的修订合并,svn 就会记住合并了哪些修订,并将再次应用这些更改。你可以通过尝试来证明这一点 - 分支、编辑 2 个文件、合并以获得冲突。仅在同一行上编辑分支文件,然后合并 - 即使目标文件没有更改,它也会引发冲突,但因为合并正在将更改应用于已从分支文件预期更改的行(即就像补丁一样,它显示了它认为要更改的行应该是什么)。实际上,您不会看到这一点,因为您不会反复拒绝合并更改。
然而,SVN 在处理重命名文件方面表现不佳,因为它将它们作为删除+添加操作进行跟踪。其他 SCM 做得更好 - 但即使它们也无法真正判断文件是否被重命名,或者被删除和添加,特别是当该文件也被修改时。 Git 使用一些启发式方法来尝试确定这一点,但我看不出它能保证成功。在我们拥有一个可以连接到文件系统的 SCM 之前,我认为这种情况将一直存在。
AFAIK, SVN does all its merging internally - the merge tools are there only for cases where there's a conflict as (obviously) it needs to tell you about it and get you to fix it.
The non-conflicting cases are based around applying patches - ie, svn will take the changes you made in a revision, and will apply those to the target. Recent versions of SVN (since 1.5) remember the merges you did previously, storing this information in a property associated with the directory. 1.6 does a much better job of handling these properties compared to 1.5.
SVN does not merge by comparing 2 trees and diffing them - see the book - except when the trees to merge are not related, only then it'll perform a diff-type merge operation (or you specify the --ignore-ancestry option). Here's a brief description of what happens.
You can see this when you merge past conflicts - once you've resolved a tricky revision merge, svn remembers which revisions were merged and will apply those changes again. you can prove this by trying it - branch, edit 2 files, merge to get a conflict. Edit the branched file only on the same line, then merge - it'll pop a conflict even though the target file hasn't changed, but because the merge is applying a change to a line that's been changed from what the branched file expected (ie just like patch which shows what it thinks the line its going to change should have been). In practice you don't see this as you don't tend to repeatedly reject your merge changes.
However, SVN does a poor job with renamed files as it tracks them as delete+add operations. Other SCMs do a better job - but even they cannot really tell if a file is renamed, or is deleted and added, especially when that file is modified as well. Git uses some heuristics to try and determine this, but I can't see it guarantees success. Until we have a SCM that hooks into the filesystem, I think this will remain the case.
有两件事:
Mercurial 确实有内部代码来进行合并,并且只有在内部“预合并”失败时,它才会调用外部合并工具。
您链接到HG Book ,它说没有用于处理冲突的内置工具(与没有内置合并不同)和 Mercurial wiki 其中指出 Mercurial 将在调用外部程序之前尝试在内部进行合并。
您链接到一个问题,其中我的答案给出了明确的合并中 Mercurials 成功而 Subversion 失败的情况。这是使用 Mercurial 和 Subversion 中的内部合并代码进行的开箱即用的比较。
Two things:
Mercurial does have internal code to do merges and it will only call out to an external merge tool if the internal "pre-merge" fails.
You link to the HG Book and it says that there is no built-in tool for handling conflicts (not the same as no built-in merge) and the Mercurial wiki where it is stated that Mercurial will try to do merges internally before calling external programs.
You link to a question where my answer gives an explicit case where Mercurials succeeds and Subversion fails in a merge. This is an out-of-the-box comparison using the internal merge code in both Mercurial and Subversion.