我在一些地方听说过,分布式版本控制系统发光的主要原因之一,是比传统工具(如SVN)更好的合并。 这实际上是由于两个系统工作方式的内在差异,还是特定的DVCS实现(如Git/Mercurial)具有比SVN更聪明的合并算法?
当前回答
SVN跟踪文件,Git跟踪内容变化。跟踪从一个类/文件重构到另一个类/文件的代码块是足够聪明的。他们使用两种完全不同的方法来追踪你的来源。
我仍然大量使用SVN,但我对我使用Git的几次非常满意。
如果你有时间,这是一本不错的书:为什么我选择Git
其他回答
SVN跟踪文件,Git跟踪内容变化。跟踪从一个类/文件重构到另一个类/文件的代码块是足够聪明的。他们使用两种完全不同的方法来追踪你的来源。
我仍然大量使用SVN,但我对我使用Git的几次非常满意。
如果你有时间,这是一本不错的书:为什么我选择Git
从历史上看,Subversion只能执行直接的双向合并,因为它没有存储任何合并信息。这涉及到获取一组更改并将它们应用到树中。即使使用合并信息,这仍然是最常用的合并策略。
默认情况下,Git使用3-way合并算法,其中包括为合并的头部找到一个共同的祖先,并利用合并两侧存在的知识。这使得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简单得多的数据模型来存储修订,因此它可以将大量精力放在实际的合并算法上,而不是试图处理=>这种实际上更好的合并。
刚读了Joel博客上的一篇文章(很遗憾是他的最后一篇)。这篇文章是关于Mercurial的,但实际上它谈论的是分布式VC系统(如Git)的优势。
使用分布式版本控制, 分布式部分实际上不是 最有趣的部分。有趣的是,这些系统从变化的角度考虑问题,而不是从版本的角度。
点击这里阅读文章。
推荐文章
- 多久向源代码控制提交一次更改?
- 如何禁用Git凭证管理器的Windows?
- Git 拉取与 Git 变基
- 在git中压缩提交是什么意思?
- 在GIT中合并2个分支
- git标签也会被推送吗?
- 嵌套的Git存储库?
- Git bash错误:无法fork子进程:没有可用的终端(-1)
- 有没有办法在SourceTree中获得两个分支的视觉差异?
- Git标记是否只应用于当前分支?
- Git分支:master vs. origin/master vs. remotes/origin/master
- 如何根据文件扩展名过滤git差异?
- 如何设置一个git项目使用外部回购子模块?
- Git同时在两个分支上工作
- 如何在Visual Studio中删除未推送的外向提交?