Subversion 曾经是我们亲密无间的战友,但自从一年前部分团队成员去了美国,我们和 Subversion 的关系就开始出现了裂痕,首先是将 Subversion 服务器架设在美国后,中国开发人员频繁进行的一些操作变得非常缓慢,本来通过追溯代码历史便可找出原因的问题,却因为网速缓慢,导致开发者将大量的时间耗费在等待服务器响应,而不是分析问题上。其次,由于缺乏 IT 基础设施方面的投资以及完善的备份策略,数次因为网络原因或者服务器宕机,导致团队无法从中国访问版本管理服务器,正常的提交、更新操作都无法进行,最严重的是版本管理服务器曾经在发布之前出现故障,导致服务器上的数据不得不回滚到九天以前,给发布带来了很大的风险。
从现象上看,版本管理服务器不在本地是遭遇速度瓶颈的主要原因,本质却是由于版本管理工具不能很好的根据团队的规模和结构伸缩。对我们而言,比较理想的版本管理解决方案是在中美两地架设服务器,加快各个操作的执行速度,服务器之间自动同步来平衡两地对于速度和代码集成的要求。然而采用 Subversion 作为版本管理工具,决定了服务器仅能架设在一地。 SVK 可以解决部分问题,但它的缺陷太多,操作起来非常不便。我们所面临的备份问题则是由于在 Subversion 的设计中,所有的元数据仅仅保存在服务器上,一旦服务器出现意外,元数据所包含的宝贵信息便无从恢复。之前的教训让我们认识到如果采用 Subversion 作为版本管理工具,就不能仅仅乐观的假设服务器不会出错,必须有详尽可行的备份计划,通过不断备份来规避风险。
Subversion 的这些天生缺陷让我们把目光投向了 DVCS (分布式版本管理工具),在这个家族中,比较成熟的产品有 Git 、 Mercurial 和 Bzr ,相比之下,由于 Mercurial 对 Linux,Mac 和 Windows 平台有良好的支持,支持通过 Web 方式访问代码库,并存在成熟的 IntelliJ、Eclipse 插件,最终成为了胜出者,时至今日,它已经在我们团队服役超过 1 年了,从 0.9.4 到 1.1.2,每一次版本的更新,都让我们愈加喜欢这个设计精巧产品。那么较之 Subversion,Mercurial 究竟胜在哪里?
快速可靠
Mercurial 带给团队的第一个体验就是快,原因很简单,由于 DVCS 的工作目录与中央仓库(Central Repository)别无二致,同样保存了全部的元数据,那么 Subversion 需要通过网络完成的操作 (诸如提交、追溯历史、更新等), Mercurial 可以在离线条件下通过操作本地仓库完成(图 -1)。
图 -1
通过减少与中央仓库的通信, Mercurial 加快了操作速度,减小了网络环境对团队的影响,非常符合我们的需求。这种速度和可靠性的提高,对于时刻与版本管理工具打交道的开发者是一种非常愉悦的工作体验。此外,包含了全部元数据的工作目录可以在中央仓库出现问题时(图 2-b)成为备用仓库(图 2-c),而整个过程只需运行一条命令即可。
图 -2
这样,在 IS 部门修复中央仓库的过程中,开发团队依然可以通过备用仓库交换修订,日常工作在没有中央仓库的情况下依然可以正常开展,中央仓库恢复后,再将宕机期间所有的修订通过备用仓库同步到中央仓库上(图 2-d),这套机制可以作为经费和硬件设施有限团队的备份方案。即便中央仓库完全损毁,所造成的损失也非常有限,避免了使用 CVCS 时将“所有鸡蛋放在一个篮子里”的风险。
便于协同工作
在日常的工作中,我们常常利用 Mercurial 灵活的分支合并来共享修改,协同工作。几个月前在印度发布产品时,我需要在新的工作站上安装开发环境,由于代码库庞大而且网速缓慢,克隆中央仓库的操作需要花费数小时才能完成(图 3-a),Mercurial 的灵活性使我可以将工作站指向已经存有代码的笔记本电脑来执行克隆操作(图 3-b),在数分钟后工作站就完成了全部的克隆操作,之后再将它指向中央仓库(图 3-c),即可正常提交 / 更新代码,大大节省了时间,提高了效率。
图 -3
在另一个场景中,由于我所在团队使用 Linux 作为开发环境,在急于验证某些功能是否在 Windows 平台可以正常工作时,我们会将代码在 Linux 工作站本地提交,再将 Windows 工作站的工作目录指向 Linux 工作站,获取更新(图 4-b)。之后,在 Windows 平台验证功能,如果功能存在问题,可以修复后再将修订从 Windows 工作站提交到 Linux 工作站(图 4-c),最终由 Linux 工作站运行测试并将全部更新同步到中央仓库(图 4-d)。Mercurial 的分布式特性让开发团队敏捷的分享修订,更有效率的开发。
图 -4
对小步前进友好
本地仓库的存在,使 Mercurial 对小步前进更加友好 。小步前进意味着开发者在不破坏任何现有功能的前提下,每次修改少量代码并提交。这两个需求让使用集中式版本管理工具的开发者常常处于两难的境地,”不破坏现有功能“与“每次修改少量代码并提交”意味着存在便于分析的细粒度需求以及开发人员必须掌握增量式的对象建模、重构,数据库设计、迁移等技术。难于小步前进体现的是团队成员经验和技术的欠缺,然而解决这些问题不是一朝一夕之功,本地仓库的存在给了开发者更大的自由,允许开发者频繁提交而无需顾忌是否每一次提交都不会破坏现有功能,在代码经过若干次提交到达稳定状态时再与中央数据库同步。通过使用 Mercurial,使得小步前进这个实践得以在团队开展,在大家体会到实践带来的好处后,再追求高质量的小步前进。
学习曲线低
Mecurial 灵活的分支合并策略使我们可以选择与 CVCS(集中式版本管理工具如 Subversion,CVS 等) 非常相似的架构(如图 -1 所示),这样,团队在更换版本管理工具后依然可以工作在相对熟悉的环境中。在 (图 -1) 所示的结构中,开发者需首先架设中央仓库,再从中央仓库克隆出工作目录,在开发过程中,开发者将修订提交到本地仓库,最后,在功能完成后将本地仓库的所有修改同步到中央仓库。除了最后一步,其余步骤和 CVCS 完全一致,开发者可以很快对 Mercurial 总体架构建立初步的认识。Mercurial 的基本命令与 CVS/Subversion 非常类似,熟悉 CVS/Subversion 的团队可以依然工作在熟悉的命令行环境。从结构到命令,Mercurial 做到了对 CVCS 用户友好,降低了学习曲线,让开发者可以相对轻松的跨出从 CVCS 到 DVCS 的第一步。如果仅仅想作一下尝试,又或者公司的政策不允许将版本管理工具从 Subversion 迁移到 Mercurial,Mercurial 还提供了 HgSubversion 插件可供选择,它可以将 Mercurial 作为 Subverion 的客户端使用,这样,既可以保留 Subversion 版本管理服务器,又可以在本地采用 Mercurial 来享受 DVCS 的种种好处,使开发者可以非常安全过渡到 DVCS 环境。
总结
毫无疑问 Subversion 是非常优秀的版本管理工具,但是它有自己的适用范围,并不是银弹。抛弃 Subversion,也不因为我们是新技术的狂热分子,而是它无法伸缩来适应团队的结构变化。对于希望尝试 DVCS 的团队,我的几个建议是:决策者首先要识别团队的痛点,对问题域有清醒的认识,而不能仅仅追赶技术潮流,其次是使用它、慢慢的接受它,如果团队仅仅止于理论方面的学习,各种方案的论证,是无法掌握 DVCS 并利用它来提高团队效率的,最后整个团队需要持续学习 DVCS 背后的设计思想,对于问题域的抽象以及丰富的插件的使用方法。这些知识将直接或间接的帮助团队提高进行代码版本管理的能力,更有效律的管理代码。
感谢
感谢我的同事杨哈达,初悦欣,乔梁和陈金洲在我写作过程中提供的无私的建议和帮助。和杨哈达的讨论让我对于DVCS 的理论有了更清楚的认识,初悦欣和我一起重构了插图,乔梁和陈金洲对于文章的结构提出了很多意见和建议。
这篇文章是我在工作中从熟悉的Subversion 迁移到Mercurial 的经验分享,在这个过程中有不适应,也曾经犯了很多错误并获得了许多经验。希望读者能从这篇文章中有所收获,从DVCS 在我们团队的实践了解到DVCS 可能带给自己团队的价值,更有信心的进入DVCS 领域。
作者简介
胡凯,ThoughtWorks 敏捷咨询师,近2 年一直从事持续集成工具 Cruise 以及 CruiseControl 的设计开发工作。 对于 Web 开发,敏捷实践,开源与社区活动有浓厚的兴趣,可以访问他的个人博客进行更多的了解。
相关阅读
[ ThoughtWorks 实践集锦(1)] 我和敏捷团队的五个约定。
[ ThoughtWorks 实践集锦(2)] 如何在敏捷开发中做好数据迁移。
[ ThoughtWorks 实践集锦(3)] RichClient/RIA 原则与实践(上)、(下)。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论