http://www.open.collab.net/nonav/scdocs/SVNIntro
Subversion 最佳实践
这是一套快速入门指南,它可以帮助您在每天的软件开发工作中充分使用 Subversion。
使用全面的存储库布局
安排存储库布局的方法有很多。由于分支和标签是普通目录,因此需要在存储库结构中对它们进行说明。
Subversion 项目官方推荐采用“项目根目录”方式,项目根目录代表项目的锚点。“项目根目录”包含三个子目录:/trunk、/branches 和 /tags。单一存储库可以只包含一个项目根目录,也可以包含多个项目根目录。
参考书目: “选择存储库布局”。
提交合乎逻辑的更改集
对存储库提交更改时,需确保更改反映单一目的:修复特定错误、添加新功能或一些特殊的任务。您提交的更改将创建一个新的修订号,此修订号可永久作为此更改的“名称”使用。您可将此修订号记载到错误数据库中,或将它用作 svn merge 的参数,这是为了便于今后撤消此更改或将它转移到其它分支中。
参考书目:第 4 章中的“Subversion 和更改集”边栏。
灵活使用事件跟踪工具
尝试尽可能多地在 Subversion 更改集和您的事件跟踪数据库之间创建双向链接:
- 如果可能,在每个提交日志信息中都引用一个特定事件 ID。
- 在事件中附加信息时(描述进度,或结束事件),为更改提供相应的修订号。
手动跟踪合并
提交合并的结果时,请务必要撰写说明合并内容的描述性日志信息,类似于:
/branches/foobranch 的修订版本 3490:4120 已合并到 /trunk 中。
参考书目: “手动跟踪合并”和“将整个分支合并到另一个分支中”。
了解混合修订工作副本
工作副本的目录和文件可具有不同的“工作”修订版本:这一特性是特别设计的,目的是允许将旧版本的对象与新版本的对象相混合和匹配。但有一些问题必须注意:
- 每次执行 svn commit 命令后,工作副本都将具有混合修订版本。刚提交的对象具有最新的修订版本,而其它对象仍为旧的修订版本。
- 不允许进行的提交包括:
- 对不具有最新工作修订版本的文件或目录不能提交删除。
- 对不具有最新工作修订版本的目录不能提交属性更改。
- svn update 可将整个工作副本统一为一个工作修订版本,此为上述第 2 点问题的典型解决方案。
参考书目: “混合修订版本的限制”。
耐心处理大型文件
Subversion 的另一个不错的功能就是在设计时没有对它可以处理的文件大小进行限制。文件以“流”的形式在 Subversion 客户端和服务器之间双向发送,并且在网络的两端通常占用较少的内存。
当然,还需要考虑大量的实际问题。尽管无需担心 KB 级别的文件(例如,典型的源代码文件),但提交大型文件可能需要花费大量时间和占用大量空间(例如,几十个或几百个 MB 大小的文件)。
开始时,请记住 Subversion 工作副本将所有版本控制文件的原始副本存储在 .svn/text-base/ 区域中。这意味着工作副本占用的磁盘空间至少是原始数据集的两倍。不仅如此,提交文件时,Subversion 客户端还需遵循(现在不可调整)某种算法:
- 将文件复制到 .svn/tmp/(可能需要花费一定时间,并且暂时占用额外的磁盘空间)
- 在临时文件和原始副本之间,或者是临时文件和空白文件(如果新添加)之间执行二进制差异操作。(可能会花费很长的时间进行计算,尽管最终只有少量数据会在网络中发送)
- 将差异发送到服务器中,然后将临时文件移入 .svn/text-base/
因此,尽管理论上对于文件的大小没有限制,您需要知道大型文件可能会需要您在客户端缓慢处理的同时耐心等待。但是,您可以放心的是,与 CVS 不同,这些大型文件不会使服务器出错,或者是影响其他用户。
解决不了解复制/重命名命令的问题
当用户对某个文件或目录执行了复制和重命名操作之后,Subversion 存储库就会跟踪该历史记录。不幸的是,在 Subversion 1.0 中,只有一个客户端子命令实际利用了此功能,即 svn log。大量的其它命令(例如 svn diff 和 svn cat)应该自动跟踪重命名历史记录,但却未实现此功能。
在所有这些情况下,基本的解决方法就是在旧版本中使用 'svn log -v' 发现正确的路径。
例如,假设您在修订版 200 中将 /trunk 复制到 /branches/mybranch 中,然后在后续的版本中将某些更改提交到 /branches/mybranch/foo.c 中。现在,您希望比较文件的 80 修订版和 250 修订版。
如果您具有该分支的一个工作副本并运行 svn diff -r80:250 foo.c,您将看到一条有关在修订版 80 中不存在 /branches/mybranch/foo.c 的错误信息。要补救,应该在您的分支或文件中运行 svn log -v 以便发现在修订版 200 之前该目录就已被命名为 /trunk/foo.c,然后直接比较这两个 URL:
$ svn diff http://.../trunk/foo.c@80 / http://.../branches/mybranch/foo.c@200
掌握创建分支的时机
这是一个容易引起争议的问题,事实上它取决于您的软件项目培养。没有规定通用的策略,仅在此描述三种常见的。
从不分支系统
(常用于还没有可运行代码的初始项目。)
- 用户将他们的日常工作提交到 /trunk 中。
- 用户开始提交一系列复杂更改时,/trunk 偶尔会“损坏”(无法进行编译或功能测试失败)。
优点:此策略非常容易遵守。新开发人员进入的门槛很低。不需要学习如何进行分支或合并。
缺点:无序的开发和代码可能随时变得不稳定。
旁注:在 Subversion 中,此类开发的风险要比在 CVS 中小得多。因为 Subversion 的提交是封闭单元式的,因而在其他人的提交过程中,签出或更新不会收到“部分”提交。
始终分支系统
(常用于需要进行大量管理和监督的项目。)
- 每个用户对每项 编码任务的创建或操作都是在私有分支中进行的。
- 编码完成后,原编码者、同级或经理将对所有私有分支的更改进行审查并将它们合并到 /trunk 中。
优点: 能保证 /trunk 始终都能极其 稳定。
缺点:编码者之间被人为隔离,会导致很多不必要的合并冲突。需要用户进行大量的额外合并工作。
按需分支系统
(这是 Subversion 项目所使用的系统。)
- 用户将他们的日常工作提交到 /trunk 中。
- 规则 #1:必须随时对 /trunk 进行编译并确保通过回归测试。将对违反此规则的提交者提出公开批评。
- 规则 #2:单个提交(更改集)必须小于同级所能审查的最大限度。
- 规则 #3:如果规则 #1 与 #2 产生冲突(如一系列小提交必然会扰乱 trunk),则用户应创建分支,然后将一系列更小的更改集提交到分支中。这样即可允许进行同级审查,又会不破坏 /trunk 的稳定性。
优点: 可保证 /trunk 始终都能保持稳定。分支和合并的问题将较少。
缺点:将添加一些负担到用户的日常工作中:每次进行提交之前,都必须进行编译和测试。