[原创]项目svn版本控制中的分支策略
by AKara 2010-06-07 @ http://blog.csdn.net/akara @ akarachen(at)gmail.com @weibo.com/akaras
结合项目运营的一些体会,浅谈一下项目中经常用到的分支策略。
从一个很旧的PDF <<Essential CVS>> 上发现了一些篇章,回头一读发现
多年前精简的原则阐述放到现在来说,仍有非常好的指导意义,基本涵盖我
打算要总结的内容了,干脆翻译一遍它。虽然用的是svn,但是应该和cvs本质
上是相同的理念~
---------------------------------------------------------------------
(翻译仓促,如需转载请先联系:http://blog.csdn.net/akara / akaras@163.com)
4.4 Branching Strategies
本章将讲述分支策略中的基本原则以及两种主要的分支原则。
并给予一些关于 何时/为何 你需要在一个项目中开辟分支的解答。
4.4.1 Branching Philosophies
关于分支的经验法则是:保持开发的主线位于trunk(主干)上;而其他的一切,
branch(分支)。问题在于如何界定哪些是开发的主线。trunk应该只包含稳定
的代码还是也可容忍不稳定的代码?是否在每个release被测试前都应该分支?
新功能应该在trunk上开发还是在一个branch上开发?
上面这些疑问都源于我们对'开发的主线'有两种不同的定义。这两种定义引出
了两种截然不同的分支原则,术语上称basically stable和basically unstable。
4.4.1.1 Basically stable
顾名思义这个分支原则主导思想是trunk只包含稳定的随时可发布的代码。
branches则用于开发新功能/修正bug/发布前的QA控制/重构/实验性质功能试点。
该原则下最严格的遵行方式为:任何未经严格QA控制的代码都不能merge回trunk。
这样便能保证任何时刻都可以从trunk上分出一个release candidate(rc),
它只需要通过少量的QA控制流程便能进入正式发布。
不那么严格的遵行方式则允许通过开发者的unit-testing的代码merge回trunk。
这种稍微宽松的方式则需要通过全套的QA控制监督才能进入正式发布流程。
Basically stable原则下有一些优点:
* 任何时刻可以分出一个release。并配以简单QA控制就加以发布。
* 因为trunk只包含稳定的代码,并且变动的节奏很慢;
所以你可以在branch上作大量的实验性改动,而不用担心merge回trunk时
会和别人的工作掺杂在一起而导致bug。
而这个原则下最大的缺点是:merge通常由QA测试员来进行而不是理解代码语义
的编写者来进行。另一个缺点是:在从一个branch往trunk merge完成后,trunk
上的改动相对于这个branch被分出去的那个版本来说,可能是巨大的。当然这两个
问题都可以通过使开发者周期性地merge回trunk而得到一定程度上的减轻;或者
遵行更为宽松的merge要求。
4.4.1.2 Basically unstable
Basically unstable原则下,要求trunk包含最新的代码,不管它的稳定性如何;
而用于release candidate的版本则应该开辟一个分支来交付。
该原则下最严格的遵行方式为:所有开发都在trunk上进行,只有rc,
bugfix branch,release等性质的事件才会开辟branch。
稍为宽松的遵行方式为则允许使用branch来进行实验性编码,重构,以及其他
特殊用途的代码开发。而往trunk merge则通常由相应branch的负责者来完成。
Basically unstable原则的优点是merge是个不常发生的事情,而且是个相对
容易完成的事情———因为是由熟悉branch代码的负责者来完成merge。
而它的缺点显然是trunk包含了不稳定的代码,可能是实验性功能,甚至连
编译都不能通过的代码。经常进行tagging可以减少这个缺点带来的影响,
所以每次对每次实验功能和重构等进行tag操作是个好习惯。更宽松的的遵行
方式是将那些bug倾向极大的代码从trunk上branch出去,为随时从trunk准备
一个release提供更好的环境。
4.4.2 Branch Styles
CVS包含创建和使用branch的一些方法,但是它不强迫使用者必须使用某种
技巧来使用。本章介绍几种使用branch的风格。
本章中的"long branch"术语指的是正在使用的branch或者经过多次merge
回trunk的已经废弃的branch。而'short branch'术语是指那些只merge一次
回trunk便废弃的branch。
当然,CVS中的'废弃'并不等于不存在;CVS允许任意时刻又重新开始使用任何
一个branch。结束或废弃一个branch只是简单地告诉所有开发者:不要再使用
它了。
4.4.2.1 Long branch, merging to branch
从trunk上往的一个正在开发的branch中经常merge内容的做法对于某些情形
非常有用:trunk不希望受到branch的改动影响,但是branch希望接收trunk上
的有用的改进部分。镜像站点就是这种情形。图 4-6 描述了这个做法:
Branch ______________________
/ ↑merge ↑merge ↑merge
Trunk ——————————————————————>
图 4-6 从trunk上往branch多次merge内容
4.4.2.2 Long branch, merging to trunk
从正在开发的branch往trunk中经常merge内容的做法对于如下情形非常有用:
branch不希望受到trunk上改动的影响,但是trunk希望融合branch上的改进。
在一个branch正在处于测试期或正处于发布前期时;这个做法会有很好的效果。
处于测试中的项目可以采取本做法,将branch上已经测试的修改merge回trunk中。
图 4-7描述了这个做法:
Branch ______________________
/ ↓merge ↓merge ↓merge
Trunk ——————————————————————>
图 4-7 从branch上往trunk多次merge内容
4.4.2.3 Long branch, merging both trunk and branch
Long branch和trunk之间也可用互相merge的做法来保证双方的改动都同时
双方得到融合。如果开发者在branch上进行着不稳定的编码工作,那可以在
每个里程碑完成时往trunk中merge,而branch也可以随时准备接受trunk上的
改动同步。当你一步步地往一些成熟的代码添加新功能的时候,这个方法可以
很好地进行版本管理。 图 4-8 描述了这个做法:
Branch ______________________
/ ↑merge ↓merge ↑merge
Trunk ——————————————————————>
图 4-8 trunk和branch互相merge
4.4.2.4 Short branches
为一个简单功能修改而开辟的独立branch我们叫它short branch。如果你希望
增加一个独立功能 / 编写实验性代码 / 准备发布版本,那这就是很理想的做法。
显然可以用系列的short branches来模拟一个long branch在branch和trunk
间相互merge的情况。通过这个方法,就避免了先从long branch中merge改动
回trunk,然后又要从trunk往long branch中merge更改的麻烦——取而代之的是
你只需从short branch中往trunk merge,然后再从trunk开辟一个新的short branch
继续如此循环,直至达到目标开发量。这种方法很适合在trunk和branch都将有
重大的变动的情形。图 4-9 描述了这个做法:
Branch _____ Branch_____ Branch_____
/ ↓merge / ↓merge / ↓merge
Trunk ———————————————————————>
图 4-9 short branches
4.4.2.5 Nested branches
CVS允许从branch上开辟branch。子branch将视父branch为trunk。上面讨论过
的trunk和branch之间的原则可以一样地继续应用。嵌套branches在将CVS用作
配置管理系统的时候非常有用。同时需要注意,减少嵌套的复杂度总能减少混淆。
如果你正在一个branch写一个新功能集合,而又需要在部分功能交付测试时继续
你的开发,你便应该在这个branch之上再开辟一个新的branch用来交付测试。
见图 4-10 描述:
Branch2.3.2.2.2___2.3.2.2.2.1___2.3.2.2.2___
/
Branch 2.3.2___2.3.2.1___2.3.2.2___2.3.2.3___2.3.2.4___
/ /
/ /___2.3.2.3.2.1__2.3.2.3.2.2__
/
Trunk ———2.2—————2.3—————2.4——————2.5——————>
图 4-10 Nested branches
4.4.3 Branch Polices
有一些一贯的原则可以帮助你利用分支来加强项目中的版本管理。脱离这些原则,
可能会让你在一团糟的分支关系中迷失方向。
拥有和遵守这些原则同时也帮助你将merge变得更加简单易操作。减低merge的成本
需要branch和trunk上的开发者进行足够的交流。
让这些原则在你的项目和团队中成为规章吧。下面是我和同事都觉得有用的
一些原则:
* 对项目有总体的(版本管理)设计。
* 开辟每个branch前确定它的目标;并尽量减少项目中有效的branch。
* 尽量降低branch方案的复杂度。CVS允许嵌套分支,但嵌套分支这种复杂情况
很少为项目带来好处:)
* 使用一致的branch命名规则来表达分支的用途。
* 注意branch和trunk的差别同步;好的设计和交流会减少这种问题发生的可能性。
一个例子是:当一位开发者改变了某函数的参数个数(更糟糕的是,参数的顺序);
但其他开发者仍未得到通知,而且没有merge,仍在用旧的参数方式来调用函数。
* 尽量避免在CVS中提交二进制文件,以便CVS进行自动的文件merge操作。
* 经常merge。显然,改动越少,merge越简单。
* 标记好每个merge点的信息,以便避免对同一个改动重复merge。
* 在trunk上的每个branch点/merge前/merge后 做好标记信息;方便随时取回
某个trunk状态下的信息。
* 使用一致的branch标记信息规则。
(翻译仓促,如需转载请先联系:http://blog.csdn.net/akara / akaras@163.com)
---------------------------------------------------------------------
说回项目中的分支策略。
假设每次运营维护期大概一周。下面以周为最短的分支周期。
我们采取的是 Basically unstable 原则,一般的最新代码在trunk上开发。
每次对外发布则开辟rc branch提交QC。然后该branch进入为期一周的buf fix mode。
用时一周左右的的改动一般用short branch的形式进行。改动完后一次性往回merge。
long branch则只用于超过两周的功能开发。每次merge back操作由branch负责人进行。
每次rc branch通过QC full tested 后将直接当作release;
freeze后的二进制档将自动提交到freeze svn仓库作为一个可回滚的发布版本,
并由SA作为最新发布的根据。