根据我的理解,SVN是“易于分支。合并困难”。这是为什么?它们如何合并有区别吗?
根据我的理解,SVN是“易于分支。合并困难”。这是为什么?它们如何合并有区别吗?
Answers:
请参阅我的Stack Overflow答案,了解非常具体的情况,其中Mercurial(和Git)合并没有问题,并且Subversion给您带来虚假的冲突。这种情况是在重命名某些文件的分支上完成的简单重构。
关于tdammers的回答,那么那里存在许多误解:
Subversion,Mercurial和Git都跟踪项目的整个存储库范围的快照。将它们称为版本,修订版或变更集没有区别。它们在逻辑上都是一组文件的原子快照。
合并时,提交的大小没有区别。所有这三个系统均使用标准三向合并算法合并,该算法的输入为
这不要紧,怎么两个分支版本中创建。自祖先版本以来,您可以使用1000次小的提交,也可以使用1次提交。重要的是文件的最终版本。(是的,这很令人惊讶!是的,很多DVCS指南都犯了这个可怕的错误。)
他还提出了一些关于差异的要点:
Subversion有一些“伏都教”,您可以在其中合并/trunk
成/branches/foo
。Mercurial和Git不使用此模型-分支直接在历史记录中建模。因此,历史记录变成有向无环图,而不是线性的。这个模型比Subversion使用的模型简单得多,并且省去了许多极端情况。
您可以轻松地延迟合并,甚至可以由其他人来处理。如果hg merge
给您带来大量冲突,那么您可以要求您的同事hg pull
与您联系,然后他就拥有完全相同的状态。因此他可以hg merge
而且也许他比您更能解决冲突。
这是在那里你需要更新的Subversion非常困难面前你可以提交。您不能只忽略服务器上的更改并继续在自己的匿名分支上进行提交。在一般情况下,颠覆的力量你玩弄一个肮脏的工作拷贝你的时候svn update
。这是有风险的,因为您没有将更改存储在安全的地方。Git和Mercurial让您先提交,然后根据需要进行更新和合并。
Git和Mercurial比Subversion更好地合并的真正原因是实现方面的问题。即使很清楚正确的答案是什么,Subversion也无法解决重命名冲突。Mercurial和Git可以轻松处理这些问题。但是,没有理由说Subversion也不能处理这些问题-集中化当然不是原因。
trunk
在SVN中工作时尚未开始工作分支。使用DVCS,您可以提交而无需共享,但是在SVN中,您svn commit
将直接影响在同一分支上工作的其他人。即使我们两个人在SVN中的一个分支上工作,我也无法提交我的工作而不必立即与您的工作合并。这使提交有些令人恐惧-这对于版本控制系统来说是令人恐惧的特性!:-)
核心问题在于这些系统表示版本化目录结构的方式。
Subversion整个系统围绕的基本概念是版本(或在svn术语中为“修订”)的概念:文件在特定点的快照。只要历史记录是完全线性的,就可以了,但是如果您需要合并两条独立开发线中的更改,svn必须比较两者的当前版本,然后在最后一个共享版本之间进行三向比较和两个头部版本。看起来很容易改变的线条可以很容易地解决,其中一个不会改变。在两个头上完全相同地偏离的线条较难,但通常是可行的;svn会说,以不同的方式偏离的行是“人类,我无法弄清楚,请帮我解决这个问题。”
相比之下,git和mercurial跟踪变更集而不是版本。整个存储库是一棵变更集树,每个变更集都取决于一个父集,其中一个父变更集可以具有任意数量的子代,并且树根表示一个空目录。换句话说,git / hg说“首先我什么都没有,然后应用了此补丁,然后再应用该补丁,等等”。当您需要合并两条开发线时,git / hg不仅知道当前每个头的外观以及上一个通用版本的外观,而且还知道过渡是如何发生的,从而可以进行更智能的合并。
使DVCS中的合并更容易的另一件事是将提交和推送的概念分开的间接结果,并且允许随时在同一存储库的任何两个克隆之间进行各种交叉合并。使用svn时,人们倾向于提交大型变更集,而这些变更集通常具有不相关的变更,因为提交也是中央存储库上的更新,会影响所有其他团队成员;如果您提交的版本不完整,每个人都会生您的气。由于大多数设置都涉及联网的svn服务器,因此提交还涉及通过网络泵送数据,这意味着提交会给工作流程带来相当大的延迟(尤其是当您的工作副本已过时且必须先拉时)。使用git和mercurial时,提交在本地进行,并且由于两者都非常有效地处理本地文件系统,因此通常会立即完成。结果,人们(一旦习惯了)就进行了微小的增量更改,然后在其生效时,一口气推十几次提交。然后,当合并时间到来时,SCM将获得更多详细信息,并可以更好地安全自动地解决冲突。
还有一些很棒的细节使事情变得更加容易:
hg mv
或hg addremove --similarity...
)重命名,而Git使用启发式,但两个都处理重命名。即使在合并的文件中有1个字符串差异,我也可能会遇到树冲突!抱歉,您必须重新学习Subversion的某些方面。
rename a b
as,copy a b; remove a
并且都在一个原子提交中完成。合并行为的差异源于对极端案例的不同处理,以及Subversion比Mercurial和Git允许更多的合并。最后,Git 在合并和登录时检测到重命名-我们也正在考虑将其添加到Mercurial中。