这篇DVCS(Distributed Version Control System)的文章, 深入浅出, 已征得原文作者的同意, 在此将他的文章翻译为中文.

传统的版本控制辅助档案的备份,追踪与同步. 分布式的版本控制让变更的分享简单容易. 如果你做的对, 你可以鱼与熊掌兼得: 简单的合并同时并可以集中版本发布.
要分布式的吗? 一般的版本控制到底发生什么问题?
没有问题 — 如果你想快速回忆的话请参考VCS版本控制视觉指引 . 当然, 有些人可能会嘲笑你还在用”古老”的系统. 但在我看来仍然是OK的: 对于任何项目来说有用版本控制系统总是正向的一步. 集中的版本控制系统在1970年代出现, 当初程式设计者有了精简型终端机(thin clients)但同时也欣羨又大又贵又快速的”big iron” mainframes(谁能不被当时风行的大小通吃8bits到1 byte的机器吸引呢?)
集中管理是简单的概念, 很自然是第一步想到的:让每个人到同一个地方签入签出, 就像集中到某个图书馆的书本上注记一样.
如此的做法对于备份,复原和同步行得通, 不过对变更的合并与分支却不太行. 当项目成长时, 通常会想将功能切割, 独立开发与测试, 再逐步将变更并入主开发线. 实际做时, 分支就很麻烦, 新的功能可能要做庞大的签入, 如果中间有任何差错, 变更变得很难管理也很难做问题排解. 当然, 集中控管的系统也总有”可能”做合并, 但并不容易: 你需要亲自确实追踪合并的动作与内容, 以避免同样的变更被做两次. 分布式的版本控制系统让分支与合并无痛执行, 因为这是此类系统的长处. (译注: SVN支持Merge Tracking后就可以避免同样的变更会合并两次以上的问题)
请看一些图解
别的教学多是严肃的命令列指令, 在此提供您视觉化的说明. 让你回想一下运用典型集中控管的版本库的状况:

每个人与主开发线同步也将档案签入主开发线: Sue加入soup, Joe加入juice, Eve加入eggs. Sue的变更必须先签入主开发线才会被其他人看到. 的确, 理论上, Sue可以另开一个新的分支让其他人测试她的变更, 可是在一般的版本控制系统(VCS)如此做很麻烦.
分布式版本控制系统(DVCS)
依分布式模式, 每位开发者有他们自己的版本库. Sue的变动存在她个人端计算机的版本库,她可以决定是否要跟Joe或Eve分享:

不过是否有可能造成像无头的圆环一样循环呢? 不会的, 如果想要的话, 每个人可以将他的变动推(push)给同一个版本库, 存疑地, 就像上述集中的模式一般. 此人为的版本库(franken-repo)包含了Sue, Joe和Eve的变动.
我希望分布式版本控制DVC(distributed version control)可以有不同的名称, 如 “独立的(independent)”, “联合的(federated)” 或 “点对点的(peer-to-peer)”. 此字 “分散”让人联想到分布式运算, 工作被分派给一群机器(如寻找外星智慧讯号的 SETI@home {可参考SETI@home台湾网站} 或做 蛋白质摺叠分析Protein folding).
而DVCS并不像Seti@home: 每一端(node)是各自独立的且是否分享由各端自我决定(在Seti, 你必须回覆你的结果)
5分钟说明主要观念
此给你基本概念; 如果你有兴趣, 可参考相关patch theory的说明书 .
核心概念
- 集中式版本控制聚焦于同步,追溯(tracking), 和备份档案.
- 分布式版本控制聚焦于变动分享; 每一变更有其 全域唯一辨识码(guid-global unique id)或unique id.
- 记录/下载以及采用一个变更被视为分别的步骤 (在集中式系统, 此三者同时发生).
- 分布式系统没有强制的架构. 你可以建立”中央管理”区或让个人保持各自端运作.
新术语
- 推(push): 将变更送给其他的版本库 (应该需要其它版本库拥有者的允许)
- 拉(pull): 从另一版本库下载同步档案变更
关键优势
- 每人都有其本地端的沙盒(local sandbox). 你可以在自己的工作计算机上修改或回覆前版, 不需要大量的签入. 你自己的工作记录都累积存在自己的版本库.
- 可离线工作. 你只有当你想分享变更时才需要上线. 否则你可随你高兴一直在自己的工作计算机上独立作业, 签入或复原, 没有所谓”伺服器”当掉或在飞机上的问题.
- 速度很快. 差异(diff), 提交源码与变更回复都在本地端即可完成. 没有因网路或伺服器不稳而必须用一年前开发版本的问题.
- 可妥善做变动的处理. DVCS针对分享的变更做建置. 每个变更都有其独一无二的辨识码(GUID)以方便追踪.
- 分支与合并很容易. 因为每一开发人员”有自己的分支”, 每一分享的变动就像交换整合. 但独一无二的辨识码(GUID)让自动合并变更与避免重复合并动作变的简单容易.
- 较少的管理. DVCS很容易执行; 没有所谓的“总在运作的”伺服器软体需要安装. 此外, DVCS也不太需要你去”加”新的使用者; 你只是去捡选你想从那里拉(pull)版本库的URLs. 这样可以避免大型项目中令人头痛的政治性问题.
关键劣势
- 仍需要备份. 有个说法是你的“备份”就是其他人有你变更资料的终端机信息. 我无法认同—如果这些其他人终端机资料并没有采用你所有的变更呢? 或是当你变更的时候他们都不在线上? 用DVCS, 你仍希望可以有台机器让你push所有的变更到那里保存“以防万一”. (在Subversion, 你有一台随时待命的机器做主要的资料贮存库, 建议您在DVCS也做一样的事). (译注: 如有兴趣了解架设与管理DVCS服务器的工具, 欢迎参考CodeBeamer+Mercurial实务操作手册 与 CodeBeamer+Git实务操作手册)
- 没有所谓的“最近的版本”存在. 如果没有集中地, 你无法马上知道是否要到Sue, Joe或Eve那取得最近变更的版本(version). 再者, 一个中央集中地才可帮助大家清晰知道最近的”稳定版本”为何.
- 没有真正的修订版号码(revision numbers). 每一版本库有依变更做出的修订版号码. 和传统的版本库不同的方法,人们依变更的修订号码做沟通: “请问你有变更号码 fa33e7b? ” (记住, 这ID是一个不好看的GUID总体唯一辨识码). 还好, 你可以用有意义的名字贴标你发布的版本.
Mercurial 快速上手(Quickstart)

你将有:
- 一个工作拷贝(working copy). 你正在编辑的档案群.
- 一个版本库. 一个目录(Mercurial的.hg)包含所有的补钉(patches)以及可转译资料(metadat:comments, guids, dates, etc.). 因为没有集中的伺服器, 所以这些资料都放在你这里.
理解更新(Updates)与合并(Merging)
在研究DVCS时有几项让我有些混淆. 第一, 有几步将造成更新(updates)
- 取得变更到版本库:推(pushing) 或 拉(pulling)
- 采用变更到档案中:更新(update) 或 合并(merging)
- 储存新版:签入/提交源码(commit)
第二, 依据变更, 你可以更新或合并:
- 当无模糊地带时,更新(Updates)发生. 譬如, 我将变更拉(pull)到一直以来都是你在编辑的档案. 因没有重叠的变更,档案将跳到最近的修订版(revision).
- 当我们的变更发生冲突时,就有必要合并(Merge). 如果我们两个都去编辑档案,最后会变成两个”分支”, 类似平行宇宙(alternate universes-多种假设同时发展的各个故事)的样子. 有个我修改的世界, 也有个你修改的世界. 在此例, 我们可能想要合并成一个单一的宇宙.

在此案,因为 (+Soup) 和 (+Juice) 为同一个母项(parent-仅一个 “Milk”的列表)的变更, 有必要做合并(merge). 经过Joe合并档案后, Sue可以做一般的 “pull和update” 即可获得Joe已合并的结果. 她不需要亲自做合并的动作. .
在Mercuril, 你可如下执行:
是的, “pull-merge-commit” 周期蛮长的. 幸运地, Mercurial有整合多指令(commands)为单一的捷径. 虽说看起来好像蛮复杂的, 但仍比在Subversion手动合并简单多了.
大多数的合并是自动完成的. 当发生冲突时, 一般可以很快被解决. Mercurial持续追踪每一变更的母/子关系(我们的合并列表有两个母项), 与”最新版(heads)”或每一分支的最近变动. 在合并前我们有两个heads;之后, 一个.
组织一分布式项目
此为一种组织方式:

Sue, Joe和Eve将变更加入一共同的分支. 他们可以跟任一人交易补丁(patches)来做”兄弟建置(buddy builds)”:嘿 老兄, 请问要试试这些补丁吗? 在推给实验分支(experimental branch)前,我需要看看此是否可行.
然后, 经维护守门员在看过,将实验分支的变更拉到稳定的分支(stable branch), 此有最近的版本. 分布式的版本控制系统(DCVS)帮助每一变更独立进行, 但也提供集中系统所有的”单一来源(single source)”. 有多种开发的模式可用, 如”pull only”,此只有维护守门员决定是否要从别人拿取变更资料, Linux的开发采用此种,或”shared push”, 此和集中管理的系统作业模式很类似. DVCS让您弹性选择要采用哪种方法来维护您的项目.
练习和严厉批评以臻至善
我是DVCS新手,但很高兴分享我目前已了解的. 我觉得SVN很好用, 但觉得去了解如何可以让合并简单容易也有趣. 我的建议是你可以从Subversion起步, 感受一下什么是团队协同作业,再实验分布式的模式. 如果你适当的筹划, DVCS可以达到集中控管系统的效果, 你也同时可享有简易合并的好处.
- Mercurial 有超优的说明. 如果在Windows上, 你有可能需要 diffing/merging software 或 TortoiseMerge (如果你已安装TortoiseSVN ).
- Darcs 有很详细的 wikibook (有一些相关变更的数学理论).
- Git 由Linus Torvalds创造. 以下为他相关DVCS有趣的演说 ;如果你在用集中管理的系统, 准备被训一顿吧:
从Linus演说影片节录:
- “How many have done a branch and merged it? How many of you enjoyed it?”
- “When you do a merge, you plan ahead for a week, then set aside a day to do it.”
- “Some people have 5, 10, 15 branches”. One branch is experimental. One branch is maintenance, etc.
- “CVS — you don’t commit. You make changes without committing. You never commit until it passes a giant test suite. People make 1-liner changes, knowing it can’t possibly break.”
所以呢…. 祝好运囉, 密切注意圣战状况…

