我在一些地方听说过,分布式版本控制系统发光的主要原因之一,是比传统工具(如SVN)更好的合并。 这实际上是由于两个系统工作方式的内在差异,还是特定的DVCS实现(如Git/Mercurial)具有比SVN更聪明的合并算法?


当前回答

刚读了Joel博客上的一篇文章(很遗憾是他的最后一篇)。这篇文章是关于Mercurial的,但实际上它谈论的是分布式VC系统(如Git)的优势。

使用分布式版本控制, 分布式部分实际上不是 最有趣的部分。有趣的是,这些系统从变化的角度考虑问题,而不是从版本的角度。

点击这里阅读文章。

其他回答

SVN跟踪文件,Git跟踪内容变化。跟踪从一个类/文件重构到另一个类/文件的代码块是足够聪明的。他们使用两种完全不同的方法来追踪你的来源。

我仍然大量使用SVN,但我对我使用Git的几次非常满意。

如果你有时间,这是一本不错的书:为什么我选择Git

One thing that hasn't been mentioned in the other answers, and that really is a big advantage of a DVCS, is that you can commit locally before you push your changes. In SVN, when I had some change I wanted to check in, and someone had already done a commit on the same branch in the meantime, this meant that I had to do an svn update before I could commit. This means that my changes, and the changes from the other person are now mixed together, and there is no way to abort the merge (like with git reset or hg update -C), because there is no commit to go back to. If the merge is non-trivial,this means that you can't continue to work on your feature before you have cleaned up the merge result.

但是,也许这只是那些太笨而不能使用单独分支的人的优势(如果我没记错的话,在我使用SVN的公司中,我们只有一个用于开发的分支)。

Put simply, the merge implementation is done better in Git than in SVN. Before 1.5 SVN did not record a merge action, so it was incapable to do future merges without help by the user which needed to provide information that SVN did not record. With 1.5 it got better, and indeed the SVN storage model is slightly more capable that Git's DAG. But SVN stored the merge information in a rather convoluted form that lets merges take massively more time than in Git - I've observed factors of 300 in execution time.

Also, SVN claims to track renames to aid merges of moved files. But actually it still stores them as a copy and a separate delete action, and the merge algorithm still stumbles over them in modify/rename situations, that is, where a file is modified on one branch and rename on the other, and those branches are to be merged. Such situations will still produce spurious merge conflicts, and in the case of directory renames it even leads to silent loss of modifications. (The SVN people then tend to point out that the modifications are still in the history, but that doesn't help much when they aren't in a merge result where they should appear.

另一方面,Git甚至不跟踪重命名,而是在事后(在合并时)计算出它们,而且这样做非常神奇。

SVN合并表示也有问题;在1.5/1.6版本中,你可以经常自动地从主干合并到分支,但是另一个方向的合并需要宣布(——reintegrate),这会让分支处于不可用的状态。很久以后,他们发现事实并非如此,a)重新整合可以自动计算出来,b)两个方向上的重复合并是可能的。

但是在所有这些之后(恕我直言,这表明我对他们正在做的事情缺乏理解),我会(好吧,我是)非常谨慎地在任何重要的分支场景中使用SVN,理想情况下会尝试看看Git对合并结果的看法。

Other points made in the answers, as the forced global visibility of branches in SVN, aren't relevant to merge capabilities (but for usability). Also, the 'Git stores changes while SVN stores (something different)' are mostly off the point. Git conceptually stores each commit as a separate tree (like a tar file), and then uses quite some heuristics to store that efficiently. Computing the changes between two commits is separate from the storage implementation. What is true is that Git stores the history DAG in a much more straightforward form that SVN does its mergeinfo. Anyone trying to understand the latter will know what I mean.

简而言之:Git使用比SVN简单得多的数据模型来存储修订,因此它可以将大量精力放在实际的合并算法上,而不是试图处理=>这种实际上更好的合并。

编辑:这主要是解决这部分问题: 这实际上是由于两个系统工作方式的内在差异,还是特定的DVCS实现(如Git/Mercurial)具有比SVN更聪明的合并算法? TL;DR——那些特定的工具有更好的算法。分布式有一些工作流的好处,但与合并的好处是正交的。 最后编辑

我读了公认的答案。这是完全错误的。

SVN合并可能是一件痛苦的事情,而且可能很麻烦。但是,先忽略它是如何工作的。没有什么信息是Git保留或可以导出的,而SVN不能保留或不能导出。更重要的是,保持版本控制系统的独立副本(有时是部分副本)没有理由为您提供更多实际信息。这两种结构完全相同。

假设你想做Git“更擅长”的“一些聪明的事情”。你的东西已经登记到SVN了。

将SVN转换为等效的Git表单,在Git中完成,然后在一些额外的分支中检查结果(可能使用多次提交)。如果您能想象出一种将SVN问题转化为Git问题的自动化方法,那么Git就没有根本优势。

在一天结束的时候,任何版本控制系统都会让我

1. Generate a set of objects at a given branch/revision.
2. Provide the difference between a parent child branch/revisions.

此外,对于合并,了解它也是有用的(或关键的)

3. The set of changes have been merged into a given branch/revision.

Mercurial, Git和Subversion(现在是本地的,以前使用svnmerge.py)都可以提供所有这三条信息。为了证明DVC从根本上更好,请指出在Git/Mercurial/DVC中可用而在SVN /集中式VC中不可用的第四点信息。

这并不是说它们不是更好的工具!

从历史上看,Subversion只能执行直接的双向合并,因为它没有存储任何合并信息。这涉及到获取一组更改并将它们应用到树中。即使使用合并信息,这仍然是最常用的合并策略。

默认情况下,Git使用3-way合并算法,其中包括为合并的头部找到一个共同的祖先,并利用合并两侧存在的知识。这使得Git在避免冲突方面更加智能。

Git还有一些复杂的重命名查找代码,这也有帮助。它不存储更改集或存储任何跟踪信息——它只存储每次提交时的文件状态,并根据需要使用启发式方法定位重命名和代码移动(磁盘上的存储比这更复杂,但它呈现给逻辑层的接口没有暴露跟踪)。