你是继续在树枝上还是在树干里发展?

假设您正在开发定期发布的软件产品。 什么是分支和合并的最佳实践? 将定期发布的分支机构分发给公众(或者你的客户),然后继续在主干上进行开发,或者将主干版本作为稳定版本,定期将其标记为发行版本,并在分支机构中进行实验性工作。 人们认为,树干被认为是“黄金”还是被认为是“沙箱”?

我已经尝试了两种方法与一个大的商业应用程序。

哪种方法更好的答案高度依赖于你的确切情况,但是我会写下我迄今为止所显示的整体经验。

总体来说更好的方法(以我的经验):躯干应该始终稳定。

以下是这种方法的一些准则和好处:

  • 在每个任务(或相关的一组任务)中编写自己的分支,那么当您想要合并这些任务并执行发布时,您将具有灵活性。
  • 质量保证应在每个分支上完成,然后再合并到主干上。
  • 通过在每个单独的分支上进行质量检查,您将确切知道导致错误的原因。
  • 该解决scheme适用于任何数量的开发人员。
  • 这种方法是有效的,因为分支在SVN中几乎是即时操作。
  • 标记您执行的每个版本。
  • 您可以开发您暂时不打算发布的function,并确定何时合并它们。
  • 对于您所做的所有工作,您可以享有提交代码的好处。 如果你只干掉了行李箱,那么你的代码很可能会很长时间没有提交,因此也就没有保护,也没有自动logging。

如果您尝试做相反的事情,并在后备箱中进行所有的开发工作,则会遇到以下问题:

  • 不断构build日常构build问题
  • 当开发人员对项目中的所有其他人造成问题时,生产力损失
  • 更长的发布周期,因为你需要最终得到一个稳定的版本
  • 不太稳定的版本

如果您试图保持分支稳定,并将干线作为开发沙箱,您将不具备所需的灵活性。 原因在于你不能在主干中select你想要在稳定版本中放置的东西。 它已经全部混在一起了。

特别是我要说的一件事,就是当你开始一个新项目的时候。 也可能有其他情况,这取决于你的情况。


顺便说一下,分布式版本控制系统提供了更多的灵活性,我强烈推荐切换到hg或git。

我已经同时使用了两种技术,而且我会说,在主干上进行开发并且将稳定点作为发布分支是最好的方法。

以上谁反对说,你会有:

  • 不断构build日常构build问题
  • 当开发人员对项目中的所有其他人造成问题时,生产力损失

可能没有使用持续集成技术。

的确,如果白天不进行一些testing,每隔一小时说一次,就会对这些问题置之不理,而这些问题很快就会扼杀发展的步伐。

在白天做几个testing版本快速折叠到主代码库的更新中,以便其他人可以使用它,也可以在白天警告你是否有人破坏了构build,以便他们可以在回家之前修复它。

正如所指出的那样,只有在夜间编译运行回归testing失败时才发现破坏的构build是纯粹的愚蠢行为,并会迅速减慢速度。

阅读Martin Fowler关于持续集成的论文。 我们用大约2000行Posix sh把自己的这个系统推广到一个重大项目(3,000kSLOC)。

我倾向于采取“释放分支”的方法。 干线是易变的。 一旦释放时间接近,我会做一个释放分支,我会更谨慎地对待。 当最终完成时,我会标记/标记存储库的状态,以便知道“官方”发布的版本。

我知道还有其他方法可以做到这一点 – 这就是我过去的做法。

都。

主干用于大部分的开发。 但是,预计将尽最大的努力来确保任何到行李箱的登机手续不会被打破。 (部分由自动构build和testing系统validation)

版本保存在自己的目录中,只有修正了它们(然后合并到主干)。

任何将使主干处于不稳定或非工作状态的新function都将在其自己的单独分支中完成,然后在完成时合并到主干中。

我喜欢并使用Henrik Kniberg在“多个敏捷团队的版本控制”中描述的方法。 Henrik在解释如何在一个敏捷的环境中处理版本控制方面做得非常出色, 他们拥有多个团队 (在传统环境中也为单个团队工作),而且没有任何意义,所以我只需发布“备忘单”是自我解释)下面:

替代文字替代文字

我喜欢它因为:

  • 很简单:你可以从照片中得到它。
  • 它工作(和规模)好,没有太多的合并和冲突的麻烦。
  • 您可以随时发布“工作软件”(本着敏捷的精神)。

而且为了防止它不够明确:开发工作在“工作分支”中完成,干线用于完成(可释放)代码。 检查多个敏捷团队的版本控制的所有细节。

Divmod的终极质量开发系统对保持系统稳定并在分支机构工作的发展过程提供了很好的参考。 快速总结:

  • 所有完成的工作必须有一个相关的票
  • 为该故障单工作完成的每个故障单创build一个新的分支
  • 来自该分支的更改不会被合并回主线干线,而不会被另一个项目成员审查

他们使用SVN来实现这一点,但是这可以通过任何分布式版本控制系统轻松完成。

我认为你的第二种方法(例如,标签释放和在分支机构做实验性的东西,考虑到干线稳定)是最好的方法。

应该清楚的是,分支机构在分支的时间点inheritance了系统的所有错误:如果将修补程序应用于主干,那么如果将分支维护为某种分支,则必须逐个分支到所有分支释放周期终止符。 如果您已经有20个版本,并且您发现了一个远在第一个版本上的错误,则必须重新应用您的修补程序20次。

分支应该是真正的沙箱,尽pipe干线也必须扮演这个angular色:标签会指示代码在那个时间点是否是“黄金”,适合发布。

除非变化太大,不稳定,否则我们正在发展,否则我们正在接近我们的产品的主要版本,在这种情况下,我们创build一个临时分支。 我们还为每个单独的产品版本创build一个永久分支。 我发现微软的分支指导文档相当有帮助。 Eric Sink 关于分支的教程也很有趣,并指出,对于我们其他人来说,对微软有用的东西可能太重了。 在我们的案例中,我们实际上使用了Eric所说的方法。

这取决于你的情况。 我们使用Perforce,通常有几个发展方向。 干线被认为是“黄金”,所有的发展发生在分支上,当它们足够稳定时,它们被合并回主线。 这就允许拒绝不切割的特征,并且随着时间的推移可以提供独立的项目/特征可以获得的稳定的增量性能。

融合和追赶到行李箱里的新function有整合成本,但是无论如何,你将会遭受这种痛苦。 大家一起在树干上发展,可能会导致一个狂野的西部的情况,而分支允许你扩大和select你想要采取苦涩的整合药片的点。 目前,我们已经将十多个开发人员扩展到了一百多个开发人员,每个开发人员都使用相同的核心组件进行多个版本的开发,而且效果相当不错。

这样做的好处是你可以recursion地做到这一点:一个大function分支可以是自己的树干,其他分支也可以。 另外,最终的版本会得到一个新的分支给你一个稳定的维护的地方。

我们正在使用干线主要发展和分支机构的发布维修工作。 它工作很好。 但是分支只能用于修正错误,没有什么大的变化,特别是在数据库方面,我们有一个规则,只有在主干上可以发生模式变化,从不在分支上。

试图根据新的开发来pipe理当前生产代码的维护充其量是有问题的。 为了减轻这些问题,一旦testing工作完成且代码准备好交付,代码应该分支到维护线上。 另外,主线应该分支以协助释放稳定,包含试验开发工作,或者容纳生命周期延伸到多个版本的任何开发工作。

只有在代码之间存在碰撞的可能性(或确定性)时,才能创build非维护分支,否则难以以其他方式进行pipe理。 如果分支机构没有解决后勤问题,它将创build一个。

正常释放开发发生在主线上。 开发人员检查进出正常发布工作的主线。 当前生产代码的补丁程序的开发工作应在该发行版的分支中,然后在补丁程序通过testing并部署后与主线合并。 非维护部门的工作应该根据具体情况进行协调。

这取决于您的开发工作的规模。 并行工作的多个团队将无法有效地使用相同的代码(中继)。 如果你只有一小部分人在工作,而你的主要担心就是砍掉一个分支,所以你可以继续工作,同时回到分支去纠正当前生产代码的错误。 这是分支的一个微不足道的使用,不是太繁重。

如果你有大量的并行开发,你会想要为每个努力都有分支机构,但是这也需要更多的纪律:确保你的分支机构被testing并准备好合并回来。 计划合并,所以两个组不会同时合并等。

有些分支正在开发中,所以你必须允许从主干到分支的合并,以便在最终合并回主干时减less意外数量。

如果你有大量的开发人员,并且了解你的情况是什么,你将不得不尝试一下。 这是来自Microsoft的一个页面,可能有点用处: http : //msdn.microsoft.com/en-us/library/aa730834(VS.80).aspx

我们遵循trunk =当前开发stream程,branch = release(s)方法。 在发布给客户的时候,我们将树干分支,并保持树干向前滚动。 您需要决定准备支持多less个版本。 你越支持更多的合并,你会在错误修复上做的事情。 我们尽量保持我们的客户在主干后面不超过2个版本。 (例如,Dev = 1.3,支持版本1.2和1.1)。

主干通常是主要的发展路线。

发行版被分支出去,通常在分支上完成实验或主要工作,然后在准备与主要开发线集成时重新合并回主干。

干线通常应该是你的主要发展来源。 否则,你将花费大量时间合并新function。 我已经看到它做了另一种方式,它通常导致了很多最后一刻的整合头痛。

我们将发布的标签贴上标签,以便我们快速响应生产紧急情况,而无需分发积极的开发。

如果你正在通过一个发行周期,大function,你被困在一个分支。 否则,我们在树干工作,并在我们构build的每一个产品发布分支。

以前的生产版本当时被移动到old_production_,而当前的版本生产始终只是生产。 我们所有的构build服务器都知道生产是如何部署生产分支的,我们用强制触发器来启动生成。

对我来说,这取决于我使用的软件。

在CVS之下,我只是在“trunk”中工作,从来没有标记/分支,因为这样做真的很痛苦。

在SVN中,我会在trunk中做我的“最前沿”的东西,但是到了做服务器推送的时候,就可以正确标记了。

我最近切换到混帐。 现在我发现我从来没有在干线工作。 相反,我使用一个名为“新function名称”沙箱分支,然后合并到一个固定的“当前生产”分支。 现在我想起来了,我真的应该把它制作成“release-VERSIONNUMBER”分支,然后再合并到“当前制作”中,这样​​我就可以回到以前的稳定版本了。

这实际上取决于您的组织/团队pipe理版本以及您使用的SCM。

  • 如果接下来的版本(下一版本)可以很容易地计划,那么你最好在后备箱里开发。 pipe理分支需要更多的时间和资源。 但是,如果下一个不能容易地规划(在更大的组织中一直发生),你可能会最终select樱桃(数百/数千)而不是分支(几十或几十个)。
  • 使用Git或Mercurial,pipe理分支比CVS和颠覆更容易。 我会去稳定的主干/主题分支机构方法。 这是git.git团队使用的。 阅读: http : //www.kernel.org/pub/software/scm/git/docs/gitworkflows.html
  • 在Subversion中,我首先应用了trunk-in-the-trunk方法。 在发布date方面有相当多的工作要做,因为每次我必须select提交(我的公司不擅长计划)。 现在我是Subversion的专家,对Subversion中的pipe理分支非常了解,所以我正朝着稳定的中继/主题分支方法迈进。 它比以前好得多。 现在我正在尝试git.git团队的工作方式,尽pipe我们可能会坚持使用Subversion。

这是我喜欢的SVNdevise:

    • 发展
      • 分支机构
        • 优点1
        • 特点2
      • 树干
    • 公测
      • 标签
      • 树干
    • 发布
      • 标签
      • 树干

所有的工作都是从开发/主干完成,除了需要自己的分支的主要function。 在对开发/主干进行testing后,我们将testing的问题合并到beta / trunk中。 如有必要,代码将针对testing版服务器进行testing。 当我们准备推出一些更改时,我们只需将适当的修订合并到release / trunk和deploy中。

可以在testing版分支或版本分支中制作标签,以便我们可以跟踪testing版和发行版的特定版本。

这种devise可以提供很大的灵活性。 这也使得我们可以很容易地在beta / trunk版本中保留修改版本,而如果某些修订版本没有通过beta版本的testing,则可以合并其他版本来发布/ trunk版本。

@Brian R. Bondy:请注意,一旦您的团队达到了在项目中并行处理的一定数量的人事任务,这不是一个解决scheme。

一旦QA部门参与QA,每个分支进行一次安装所需的努力就太高了。 认为SOA /客户端/服务器/ Web服务/数据库,所有这些都必须提供每个分支

这个解决scheme缺乏整合阶段。

我们使用的方法是Perforce方法,在Laura Wingerd的伟大着作中详细讨论了这个方法:

http://oreilly.com/catalog/9780596101855/index.html

虽然本书以执行为中心(Wingerd是Perforce产品经理),但这些概念可以应用于任何或所有VCS。

perforce方法(和平台)为我们提供了很好的服务。 它被用在很多公司(谷歌,Intuit,我听说,微软Windows本身)。

这本书非常值得一读。

阅读: http : //oreilly.com/catalog/practicalperforce/chapter/ch07.pdf

对于颠覆公约问题恕我直言,没有一个通用的答案。

这真的取决于项目和公司使用它的dynamic。 在一个非常快节奏的环境中,当一个版本每隔几天就会发生一次,如果你试图虔诚地标记和分支,最终会得到一个难以pipe理的版本库。 在这样的环境下,分支机构何时需要的方法将创造一个更加可维护的环境。

另外 – 根据我的经验,从纯粹的pipe理angular度来看,在您select时,可以在svn方法之间切换。

我所知道的最好的两种方法是在需要的时候使用分支,在每个任务中使用分支。 这些当然是完全相反的。 就像我所说 – 这是关于项目dynamic的。