dvcs(git / mercurial)的分支和合并支持相比svn更好吗?

13

许多有关分布式版本控制系统的文章声称其支持更好的分支和合并是从svn转移到分布式版本控制系统的原因之一。这些系统究竟如何以不同的方式进行分支和合并,使得它更加优越?


我经常想到同样的问题。在我读过的每篇文章中(主要是关于Git的),它都只是作为一个简单的事实陈述,没有支持证据或例子。 - nickf
@nickf:为什么页面右侧的所有相关SO问题都没有回答你的问题?这个问题在SO上已经被回答了很多次。 - VonC
@VonC,令人惊讶的是,这是我看到的第一个关于它的问题。不过,从右边的“相关”栏目来看,我理解你的观点。 - nickf
@nickf:我的意思是,我已经在2010年(三月)的这个SO问题中声明过,这个问题已经被反复回答了很多次:https://dev59.com/JEzSa4cB1Zd3GeqPps2I(请看评论)。 - VonC
可能是为什么Mercurial比Subversion更容易进行分支和合并?的重复问题。 - Martin Geisler
6个回答

11

历史上,git 和 svn 在合并跟踪方面的区别在于:git 有合并跟踪功能,而 svn 直到版本1.5之前根本没有。如果你想进行合并操作,你必须始终明确指定要合并的具体变更内容。如果你将一个分支合并到另一个分支超过一次,你就必须手动跟踪哪些修订版本已经被合并,手动选择尚未合并的变更,以避免冲突。如果您曾使用cherry-pick命令选取任何更改,则祝你好运。

从版本1.5开始(发布于2008年),如果你的客户端、服务器和仓库都是最新的,那么svn可以表现得更加智能;它使用属性来跟踪分支的来源以及已经合并到其中的变更。结果是,在许多情况下,你只需要执行svn merge BRANCHNAME就可以做正确的事情。但由于它的“附加”性质,它仍然不够快,并且不是完全健壮的 (参见这里)。另一方面,由于其DVCS性质,Git 必须很好地处理合并场景,因此它从一开始就设计了适合此任务的数据结构(如它使用的特定类型的有向无环图)和算法(如递归合并和章鱼合并)。


6
与普遍看法相反,分布式版本控制系统与Subversion的集中式模型并不是导致差异的原因。集中式模型本身并没有使分支和合并变得低劣。
我认为Subversion在决定将代码库目录结构、分支和标记(以及所有其他代码管理模式)建模为单一的统一目录树时犯了一个严重的设计失误,这使得可靠检测分支活动的问题比如果分支在模型中是显式的要困难100倍。

5
不要忘记版本控制系统中的人性因素。今天早些时候,我创建并删除了3个不同的本地git分支,因为这是最少干扰地解决主分支问题的方式。在集中式版本控制上尝试这样做,你可能会被服务器管理员训斥或者收到一堆愤怒的电子邮件,如果你有权限的话。事实上,你可以在私有repo中拥有分支,这消除了使用分支的许多文化障碍。集中式系统使用的算法正在赶超DVCS。这些人类因素将保持不变。

3

来自Joel's hginit

这就是区别。假设你和我在一起编写代码,我们创建了一个分支,然后各自进入我们的工作空间并单独对该代码进行了大量更改,因此它们已经有很大不同了。

当我们需要合并时,Subversion试图查看两个版本——我的修改代码和你的修改代码——并尝试猜测如何将它们合并成一个巨大的混乱。它通常会失败,产生许多“合并冲突”的页面,这些页面实际上并不是冲突,只是Subversion无法弄清楚我们所做的事情的地方。

相比之下,在Mercurial中单独工作时,Mercurial会忙于保留一系列更改集。因此,当我们想要合并我们的代码时,Mercurial实际上拥有更多的信息:它知道我们每个人都做了哪些更改,并且可以重新应用这些更改,而不仅仅是查看最终产品并尝试猜测如何组合它们。


1
据我所知,svn是在cvs的基础上构建的。CVS将当前版本保持完整,并反向差异到旧版本。当您在svn(或CVS)中进行合并时,它会从要合并的两个文件中直接查看当前文件内容,并尝试将它们合并在一起。相比之下,git/mercurial会保留每个版本产生的方式的记录,因此工具有更多信息可以做出明智的决策。我认为区别在于git/mercurial会尽力确保合并易于操作(从工具角度),而svn则不会。 - Chris Cleeland
1
即使git有更多关于每个开发人员所做的内容的信息,当两个开发人员更改相同的代码时,它仍然会创建相同的冲突,对吗?比如我们有一个变量,两个开发人员分别重构该变量并将其名称更改为不同的名称。这仍然必须是合并冲突,对吧? - Samuel Neff
@Samuel 是的,但并不是所有的冲突都像你提到的那个一样根本性的。其中一些是“虚假的”,可以通过更好的合并算法来避免。 - hobbs
@hobbs,理论上我不反对,但我也记不得在SVN中曾经遇到过可以自动解决的冲突。 - Samuel Neff
我删除了之前的评论,因为正如@nmichaels所指出的那样,我搞反了。 - Marcelo Cantos
我进行了一些测试,并发现 SVN 并不存储版本,而是存储增量(对一个 250kB 的文件进行两次提交和少量编辑后会产生一个约 95kB 的修订版(≈gzip),然后是一个 1/2kB 的修订版),同样的 hg 也是如此(单个 92 kB 的数据文件)。另一方面,Git 存储所有内容的完整版本(两个 100kB 的 blob 文件)。因此,虽然我的原始观点有些偏差,但并不完全错误,Joel 的帖子仍然没有意义。 - Marcelo Cantos

2

在SVN中,分支或标记仅是将特定目录及其子目录复制到同一存储库内的另一个位置。然而,在Git中,分支(和标记)被描述为元数据(类似于CVS),但不是将所有这些数据放入单个文件中,而是使用许多文件(允许更快的更新,因为您无需重写大型“foo.c,v”文件)。此外,Git大量使用指针,所以当某些内容发生变化(例如进行提交)时,实际上需要更新的内容很少。(http://eagain.net/articles/git-for-computer-scientists/)


0

区别在于大多数分布式版本控制系统使用的存储库格式 - 有向无环图。

SVN只会将您的历史记录存储在一系列行中,每个分支都是自己的一行。但是,DVCS将其存储在包含更好合并信息的DAG中。


1
你能详细解释一下吗? - Samuel Neff
很遗憾,没有 ASCII 艺术的帮助,我并不擅长制作 ASCII 艺术。 - alternative
@Samuel,这里有一个相当不错的描述链接 - Karl Bielefeldt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接