SVN合并有何困难?


28

可能重复:
我是Subversion极客,为什么我应该考虑或不考虑Mercurial或Git或任何其他DVCS?

有时,您会听到有人说分布式版本控制(Git,HG)本质上比集中版本控制(如SVN)更好,因为在SVN中合并非常困难且痛苦。关键是,我在合并SVN方面从未遇到任何麻烦,并且由于您只听说过DVCS倡导者而非实际SVN用户提出的主张,所以这往往使我想起电视那些令人讨厌的广告,试图让演员冒充假装您已经拥有并且可以正常工作的东西很难卖给您,从而卖给您不需要的东西。

总是提出的用例是重新合并一个分支,这再次使我想起那些稻草人产品广告;如果您知道自己在做什么,则一开始就不应该(也永远不必)重新合并分支。(当然,当您从根本上做错和愚蠢的事情时,这很难做到!)

因此,撇开荒谬的稻草人用例,SVN合并中有什么比DVCS系统中合并更难?


6
我尚未在一个环境中工作,在该环境中,合并了数月之久的分支,并且使用分布式版本控制。我曾经在这样的地方工作过的唯一分支使用过TFS / Subversion。我希望这么长寿的分支机构也很难与DVCS合并。
奥德

13
@MasonWheeler我很困惑。那么,您将VCS用于什么呢?我已经看到并阅读了(众多)推荐的一种做法是拥有功能分支。在这种情况下,必须合并回主干。还是我误会了什么?(是的,树的隐喻被打破了,但从IMO开始并不是那么有用)
Andres F.

9
@MasonWheeler:我想您从字面上看这棵树的类比。
whatsisname 2012年


8
@MasonWheeler,如果您从未听说过合并回主干,那么您有多少种不同的开发环境?一些商店有稳定的主干和实验分支,在这种情况下,经常将樱桃挑选成功的特征恢复为稳定。
itsbruce 2012年

Answers:


25

这是因为svn缺少正确的数据结构来准确确定两个分支机构的最新共同祖先。对于只合并一次的分支来说,这没什么大不了的,但是在多个分支被多次合并的情况下,可能会导致许多错误的合并冲突。

我对svn的关注不是很紧密,但是我的理解是那些特定的技术问题已在最新版本中修复。但是,它的修复还不足以消除这个神话,而尝试DVCS进行合并的人由于其他原因而坚持使用它。


46

如果您知道自己在做什么,则一开始就不应该(也永远不必)重新合并分支。(当然,当您从根本上做错和愚蠢的事情时,这很难做到!)

而这正是您困惑和整个问题的根源。

您说合并分支“根本上是错误的和愚蠢的”。好吧,这正是问题所在:您将分支视为不应合并的事物。为什么?因为您是SVN用户,所以知道合并分支很难。因此,您从不这样做,并且鼓励他人不要这样做。您已经接受过避免合并的培训;您已经开发了避免合并的技术。

我是Mercurial用户。即使在我自己的项目(我是唯一的开发人员)中,我也始终会合并分支。我有一个发布分支,已将其修复。好吧,我将其合并回主线,以便修复程序在那里进行。

如果使用的是SVN,我将采用完全不同的代码库结构。为什么?由于SVN使得合并变得困难,因此您要开发成语和技术来避免进行复杂的合并。

DVCS使复杂的合并变得容易,因为它们是默认状态。在DVCS中,所有事物或多或少都是一个分支。因此,它们的整个结构都是从头开始构建的,从而使合并变得更加容易。这样,您就可以开发每天使用合并的工作流,而不是从未使用过合并的SVN工作流。

一个简单的事实是:您应该以不同于SVN的方式使用DVCS。对于这些非常不同的版本控制系统,应使用适当的习惯用法。在SVN中,您采用不涉及合并的成语,因为合并很困难。在DVCS中,您会采用经常使用合并的惯用语,因为它们没什么大不了的。

适合正确工作的正确工具。

问题是,合并为中心的工作流程是很多更好,更容易比SVN式的工作流程,你不合并的事情来使用。更容易看到将release分支中的内容带入dev分支的时间。更容易看到分支之间的各种相互作用。为事物创建测试分支很容易,然后在测试不起作用时将其剪掉。等等。

的确,乔尔(Joel)对此解释得比我好得多。您应该对此有所了解。


2
相反,我从未受过“避免合并分支”的训练。坦白地说,直到我开始听到DVCS人们谈论它时,这才是我从未真正经历过的事情,而我的直接反应是(现在仍然是)“你是疯了还是什么?”
梅森惠勒

14
@梅森:那怎么不训练?您已经接受过以SVN样式使用SVN的培训。SVN样式是使用合并。因此,您被训练为不使用甚至不考虑合并。这就是为什么它从未发生在您身上;因为您使用的系统很困难。
Nicol Bolas 2012年

5
“未接受培训”与“未接受培训”之间存在很大差异。
梅森惠勒2012年

7
@MasonWheeler:不,没有。如果没有正确地教您如何做某事,那么您就暗中受训了不做某事。您可以使用成语来解决问题。因此,您不能使用它来解决问题。效果与被告知不进行合并没有什么不同,因为即使您愿意,您也不知道如何合并。您一意孤行地将一个好的论点视为“相同的疲倦的老地方”就证明了这一点。您不认为合并是一种工具;您将其视为例外或异常情况。值得质疑而不是使用的东西
Nicol Bolas 2012年

8
@MasonWheeler:你是谁来决定“ 他们做错了 ”?您不使用DVCS,因此您没有DVCS工作流程的经验。您不知道它是否对程序员有帮助,因为您没有使用它的经验。那么,您仅凭SVN不允许它说什么“错”呢?这就像在说类,虚函数和模板是错误的,因为C没有它们。
Nicol Bolas 2012年

20

如果遵循正确的哲学,SVN合并将不会太困难...

我在大多数其他答案中看到的似乎是一段时间以来没有使用SVN的人。正如某人准确地提到的那样:“它还没有尽早消除神话。”

从我最近在继承的旧项目中使用SVN 1.6到1.8的当前经验来看,SVN在使合并变得更加容易方面已经走了很长一段路。但是,它并不是万无一失的,我认为它不会轻易使用户背离预期的用途。

虽然我非常了解SVN,并且在此期间也尝试了Mercurial进行个人项目,但在此项目之前,我从未在SVN中做过很多分支工作。开始时有很多试验和错误,并且遇到很多意外的合并冲突。

最终,尽管如此,我意识到每次遇到一个问题(或其他问题),都是因为我做的事情不正确(又称“ SVN方式”,可以说是正确的版本控制方式)。我相信这就是困难所在:您无法以无组织的方式做任何想做的事情,并且期望SVN完美地工作,尤其是合并时。合并需要用户严格控制,然后才能显示出真正的能力。

我注意到以下是强烈建议(如果不是要求的话),用于干净使用合并:

  • 使用最新版本的SVN(我认为1.6或更高版本)。越来越多的自动化和检查为您完成。
  • 使用默认的“主体,分支,标签”结构,并应用其基本原理(不要提交标签)。SVN不会为您检查任何内容。如果将标签用作分支(这是我在其中找到项目存储库的状态),它仍然可以工作,但需要保持一致。
  • 了解什么是分支以及何时创建它们。与标签相同。
  • 保持分支分支与其源分支(通常是主干)最新,但您可以从技术上从任何分支分支出来。如果您希望SVN自动合并,则这是强制性的。如果事情不是最新的,并且工作副本中有待定的修改,SVN 1.8实际上会阻止您自动合并(此行为在1.8.5中似乎又消失了)。
  • 进行“适当的”提交。它们仅应包含对非常特定概念的修改。它们应尽可能包含少量更改。例如,您希望单个提交包含对两个独立错误的修改。如果您已经修复了两者,并且它们都在同一个文件中,则应该存储一个错误的更改,这样您就可以先提交另一个错误的更改,然后再提交第二组更改。请注意,TortoiseSVN可以通过“提交后还原”轻松实现这一点。
    • 这样做可以还原特定的独立更改集,并且可以仅将这样的更改集合并到另一个分支中。是的,SVN允许您合并精选的修订。
  • 如果您曾经使用子分支(分支主干,然后分支该新分支),请遵循层次结构。如果您使用中继线更新子分支,反之亦然,那么您会有些痛苦。合并应该在层叠结构中向上或向下进行。
    • 经过几个月的试验,我可以保证这可能是最重要的部分。尝试从同一主干创建两个子分支,然后合并各个子分支之间的位,或者有时合并任一侧的子子分支之间的位。这会使SVN(或用户)跳闸。如果您要合并特定的修订版本,则可以正常运行。自动合并可能会遇到麻烦。
    • 我在将子分支A与主干同步,然后尝试将某些内容从子分支A合并到子分支B时遇到了麻烦。SVN似乎认为“从主干同步”修订版应合法地合并到子分支中B,这导致大量冲突。
  • 尽可能从分支的根开始合并。否则,SVN将只跟踪的子文件夹中进行的合并的,当你这样做从根本尝试自动合并,可能会遇到关于丢失未合并修订的警告。只需将它们从根目录合并即可解决此问题,但最好避免混淆。
  • 请注意您提交到哪个分支。如果您使用Switch将工作副本通过时间指向各个分支,请确保要提交到哪里。
    • 如果您真的不希望该分支中的更改,那就特别糟糕。我仍然不清楚那个,但是根据您如何摆脱它/将它转移到正确的分支(还原,合并)中,您可能会感到混乱。它是可修复的,但是您必须逐个合并合并版本以避免或立即解决潜在的冲突,或者您必须在自动合并后修复可能更复杂的冲突。
  • 不要让分支保持太久不变。实际上,这不是时间问题,而是分支和主干已提交多少修订,以及其中进行了多少更改。两个分支之间的合并(三向合并)始终会与分支之间的最新通用修订版进行比较。两者之间的更改越多,自动合并失败的更改就越多。当然,如果同时更改代码的结构(移动或重命名的文件),则情况会更糟。

如果您不遵循上述规定,很可能会发生冲突。它们总是可以解决的,但是花时间却不是很有趣。

哦,关于合并的另一件事,从我阅读和尝试过的所有内容来看,SVN确实很烂:删除/移动/重命名的文件/文件夹。显然,SVN仍然无法处理在一个分支中被重命名,删除或移动的文件,而其原始版本在另一个分支中进行了修改……然后将它们合并在一起。它只是不知道文件以一种方式到达哪里,而将以另一种方式“忘记”更改。一项更改显然无法解决(删除或更改文件,不能同时进行),但是将更改应用于已移动/重命名的文件应该可以,但不能。希望此问题能尽快解决。

因此,总而言之,SVN合并容易吗?我猜不会。当然,这不是随意的。它是?我不这么认为。当您以错误的方式使用它时,它只会吐回您的脸上,并且对您正在做的事情没有足够的考虑。

基于此,我可以理解为什么人们会偏爱Mercurial(例如),因为从我的经验来看,对这些事情比较宽容,并且一开始就将所有内容自动化(至少是从我开始使用的早期版本开始)。SVN已经流行了很多,因此不再值得再猛烈抨击了。


树冲突-是的,尽管TBH与其他所有SCM一样,但SVN很难解决这些冲突。Git有一些试探法,试图弄清是否已重命名或移动的文件是相同的,但是(总是不能!)总是正确的。我认为SVN应该做出一些努力,以使解决这些冲突更容易理解。
gbjbaanb 2014年

@gbjbaanb:它确实像Mercurial一样提供“修复动作”,尽管它不提供启发式方法。您需要告诉它实际上哪些删除和添加的文件是相同的。绝对有改进的空间。
leokhorn 2014年

当您是唯一在项目上工作的人时,所有这些听起来都很棒。但是,如果您有一支规模庞大的团队,并且他们都在使用“ SVN方式”(似乎没有人就具体内容达成共识)进行合并仍然是PITA。事实是svn并不能很好地支持分支工作流程。“ SVN方式”将是什至不创建分支并使用瀑布式SDLC。话虽这么说,过去我在大型项目上与Git合并时遇到了问题,有几个人在工作。但是,他们似乎仍然没有那么痛苦。
ryoung 2015年

我的经验是,如果您与不关心版本控制系统工作原理的人员一起工作,那么SVN每天都将更易于使用。我仅在几个DVCS团队中工作,但总是有相当一部分团队没有良好的版本控制行为,并且它会污染所有人的资源库。在Subversion中,未经培训的人员通常会远离分支机构,因此他们会得到“专家”的帮助,并对其进行适当的管理。当然,这种经历是我自己的,我只希望与知道他们的工具如何工作的程序员合作……
dash-tom-bang

5

内部数据模型根本不同。

从根本上讲,在SVN中,当您查看分支的历史记录时,您只会看到该分支中发生了什么。因此,当您从一个分支合并B到另一个分支时,分支A的历史记录A将包含一个大型提交,其中包含B自分支以来已明确进行的所有更改。

在SVN的第一个版本中,如果必须再次将分支合并B到分支中A,则必须手动指定B要合并的分支修订版本范围,以避免将相同的修订合并两次。聪明的开发人员当然会使用诸如“在B:1234中合并”的提交消息。

SVN 1.5“修复”了这个问题。但这并没有改变从根本上应用合并的方式。它仅向分支添加了一些额外的元数据A,从而使SVN知道版本1234已被合并,从而使SVN能够自动选择正确的版本范围。

但是,对于基本上不支持跟踪已合并内容的数据模型,此解决方案基本上是一种解决方法。

合并两个分支是一个相对简单的示例。但是想像一下这种更复杂的情况

  1. A从创建分支trunk,并在此处进行一些提交
  2. BA这里创建分支并在此处进行一些提交
  3. 在做了几提交trunkA
  4. 合并Btrunk
  5. 合并AB
  6. 合并Atrunk
  7. 合并Btrunk(这不应该真正做任何事情)

使用元数据模型正确处理此问题变得非常复杂(我不知道SVN是否确实能够正确处理此情况,并且我不愿意对其进行测试)。

在git中处理这种情况非常简单。

在git中,每次提交时,代表该提交的内部对象都包含对前一个头部的引用。当您在一个分支中合并时,提交包含对要合并的所有分支的前一个头的引用(您可以在git中一次合并多个分支)

因此,当您在git中检查单个提交的历史记录时,您可以看到所有历史记录,可以看到它何时被分支,何时被合并,还可以看到分支和合并之间的两个分支的历史记录。

因此,当合并已部分合并的分支时,确定已合并的内容和未合并的内容非常简单。

我没有使用Mercurial的经验,但是我怀疑它的内部工作原理与git类似。

因此,从根本上来说,对于SVN来说,使分支便宜是一个设计目标。但是在git中,使合并便宜是一个设计目标。

最后,上一次我使用SVN时,它无法处理合并,在一个分支中重命名文件,然后在另一个分支中修改文件。


1

我做了相当多的SVN合并-包括长期运行的开发和发布分支。总的来说,我幸存下来。合并总是很棘手,但是对于DCVS来说,缺点并不可怕-一切都是本地的,因此只需更新到已知的良好修订并继续进行即可。SVN大量发生在服务器端,因此恢复很丑陋-通常它涉及清除本地副本,然后签出新的干净分支以再次尝试。就我而言,这还不错-到SVN盒的千兆连接很有帮助。但是我们有些承包商对此感到很麻烦,因为他们的连接速度很慢,所以一切都花了很长时间,包括合并。


根据慢速连接的情况推断,在进行大型更新时,从异地远程服务器工作也会导致糟糕的掉线连接错误> <根本不好玩。
jxramos

-1

是的,我也是。我目前有12个VM,分别用于我正在工作的项目的不同版本(分支)。当我必须修复旧版本中的错误时,请修复该错误,然后将该提交合并到分支中以获取较新版本。但这现在正在重新合并整个分支,这就是我在这里所说的。

这就是有关git的一件非常好的事情。它不是关于DVCS的继承,而是git擅长的。您可以合并特定修订版本从任何分支到另一个分支。它基本上只接受diff并将其应用于其他分支,但是会进行跟踪并且更加自动化。

因此,如果您拥有分支2.0和分支3.0,并在2.0中发现了一个错误,则可以在2.0中对其进行修复,并采用可解决该问题的修订集并合并这些修订到3.0分支中。我不相信SVN除了手动获取每个修订版的差异并应用它们之外,没有其他方法可以做到这一点

当然,自动合并算法似乎也可以更顺畅地工作,并且git是完全基于“为所有事物创建分支”模型构建的,因此分支在其中确实非常平滑和容易。经常以分支的轻量来进行分支似乎很自然


而且,我想像水银具有类似的功能
Earlz 2012年

2
实际上,您可以在SVN中执行完全相同的操作。我一直都这样做。SVN Merge命令可以从其他分支提取修订(或修订范围)并将其应用于您的工作副本,然后提交。
梅森惠勒2012年

2
@MasonWheeler请记住,许多反svn情绪都针对1.5之前的版本(当svn进行合并跟踪时)。当然,其中很多只是毫无意义的狂热……
yannis 2012年

3
@MasonWheeler另请参阅stackoverflow.com/a/4215199/69742该帖子归结为DVCS,用于跟踪更改集而不是版本。变更集本质上易于接受和合并...版本不是很多,因为它们需要上下文
Earlz 2012年

@MasonWheeler哦,这一个:stackoverflow.com/questions/2471606/...
Earlz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.