大多数的版本控制系统牵涉以下的观念, 有可能用词有点不同.
基本设定
视觉化案例
在此故意给您高阶的说明:大多的教学指引都给你一堆文字指令. 让我们走过高阶的观念,不在指令语法上打转( Subversion手册 永远都在那里, 不用担心). 有时去试探到底有什么可能性总是不错的.
签入/提交(Checkins)
最简单的情境是签入一个档案(list.txt)且花时间去修改它.

每次我们签入一个档案的新版, 我们就会得到一个新修订版(new revision-每个revision的内容含多个档案at different version) (r1, r2, r3, etc.). 在Subversion你将会做:
svn add list.txt
(modify the file)
svn ci list.txt -m "Changed the list"
此 -m 旗标(flag) 使用来做此签入的说明.
签出与编辑
实作上, 你有可能不是一直签入档案. 你应该是签出, 编辑再签入. 这样的周期看起来如下:

如果你不喜欢你做的变更, 想重头来的话, 你可以回复到前一版本再重新来过(或就此停止). 当签出时, 原始设定让你取得最近的修订版本(revision). 如果你想要的话, 你可以指定所要的修订版(revision). 在Subversion, 执行:
svn co list.txt (get latest version)
...edit file...
svn revert list.txt (throw away changes)
svn co -r2 list.txt (check out particular version)
差异(Diffs)
主开发线(trunk)有档案变更的历史纪录. 差异是你编辑(editing)的变更内容 : 想像你可以 “剥下” 他们然后将他们放入一个档案:

例如, 从 r1 到 r2, 我们加入eggs (+Eggs). 想像剥出红标然后将其放入r1, 以变成r2.
又如要从 r2到 r3, 我们加入 Juice (+Juice). 由 r3 到 r4, 我们去掉 Juice 并加入 Soup (-Juice, +Soup).
大多数的版本控制系统 储存差异(DIffs)而非 所有档案的内容. 如此可以省磁碟空间: 4个版本并非指有 4个复制; 我们有1个复制和4个小小的差异. 很简洁, 是吧?
在SVN, 我们如下做两个修订版(revisions)的差异:
svn diff -r3:4 list.txt
差异帮助我们看到变更内容(”你如何再次修正bug?”) 甚至用到一个branch和其他的比较.
加码问题: r1 到 r4的差异(diff)是?
+Eggs
+Soup
请注意“Juice”甚至完全没出现 — 若直接从 r1 跳到 r4 根部不需要此变更, 因为 Juice 被Soup盖掉了.
分支(Branching)
分支让我们拷贝程式码到一个独立的档案夹随意修改运用:

譬如, 我们可以开一个分支来实验新想法: 疯狂的事情像加入Rice和 Eggo waffles. 要看你用的是什么版本控制系统,有的系统在你开分支时会变动版本的号码. 好了, 现在我们有一个分支, 我们可以变更我们的程式码并实验我们的怪怪想法. (“嗯..waffles? 我不知道老板会怎么想. 打赌用Rice应该安全才对) 由于我们是在分开的分支上行事, 我们可以独立修改或测试, 看看这些修改会不会伤害其他的部份. 且在分支里的修改都有版本控管的历史纪录.
在Subversion,你可以很简单地将一个目录做个copy另取名字, 就可以开一个branch了.
svn copy http://path/to/trunk http://path/to/branch
如此分支不是个太艰深的观念: 假装你已拷贝你的程式码到另一个目录. 你有可能已将学校的项目的程式码做了分支, 确保你有一个安全的环境尝试失败版本以便如果搞砸了可以回复没问题的版本.
合并(Merging)
分支听起来很简单,对吧? 不过, 不见得喔 — 解决如何将一个分支的变更合并到另一个可以说很伤脑筋.
让我们假设要将 “Rice” 从我们实验性的分支并入主开发线(mainline). 我们要如何做呢? 做 r6 和 r7的差异分析(diff)然后将差异并到主线?
错错错. 我们只想取用在分支上做的变动. 意思是我们做 r5和r6的diff, 然后将diff送到主开发线 (main trunk):

如果你做r6 和 r7的差异分析, 我们将漏掉 “Bread” (译者注:因为r6和r7的diff将为-Bread, +Rice, 将这个diff加到r7, r8将少了Bread),而”Bread”应该在主开发线上. 这是精巧之处 — 想像从实验性branch“剥出”的变更(+Rice)并加进去主线. 主线上也许有别的变更, 如此做就没问题了-我们只是插入Rice功能.
在Subversion, 合并和差异分析非常相近. 请在主线上, 执行以下指令 :
svn merge -r5:6 http://path/to/branch
此在实验性的分支上所做的指令diffs r5-r6并将此diff加到目前所在. 不幸地, Subversion并没有简单的方法来追踪已做过那些合并,如果你不小心, 有可能会重并同样的变更. merge tracking为SVN改善计画中的功能, 目前我们劝你做好变更记录,提醒自己”r5-r6变动已合并到主开发线了”. (译者注:SVN1.5后已经开始支援merge tracking功能)
冲突(Conflicts)
大部分的版本控制系统可以自动合并一个档案不同地方的变更. 当有些变更显然无法黏合时冲突就出现了: Joe想要去掉eggs以cheese替代(-eggs, +cheese), 而Sue 想要以hot dog 替代eggs(-eggs, +hot dog).

此时竞赛产生: 若 Joe 先签入, 系统可自然接受此变更 (而后Sue就无法做她要的变更了).
当变更的地方相同且有像这样的冲突时, 版本控制系统将可能呈报冲突讯息(conflict)而不让你签入— 此时如果你是Sue, 你可以决定是否要签入一个解决(resolves)两难的新版本. 处理方法可为:
- 重新导入你的变更. 先同步到最近的版本(r4)然后再到此最新版做你要的变更: 到此已经有cheese的列表加入hot dog.
- 以你的变更去覆盖别人的变更. 将最新的版本(r4)签出,将你的版本内容拷贝过去 , 再签入. 结果, 这将把cheese换成hot dog.
虽然冲突不会常常发生, 但蛮恼人的. 通常我采用先同步到最近版本再将我的变更加进去.
标籤(Tagging)
谁曾想过版本控制系统竟然有Web 2.0的观念? 很多系统让你在任一想要的版本贴标籤tag(label)以方便参考. 如此你可以说参考”“Release 1.0″而不用指出在系统内特有的建置号码(build number):

在Subversion, 标籤跟分支编辑方法类似,只要你想要做即可执行; 此功能存在乃为了清楚之后所有版本的发展, 所以你可以完全清楚看出在 version 1.0的发布版本中内容为何. 且且就终止于此. 没有别的地方可去了. (译注: 也就是说标籤具有”冻结”的作用, 不会看到不相干的资讯)
(in trunk)
svn copy http://path/to/revision http://path/to/tag
实作的案例: 管理Windows开发程式
我们猜想Windows开发可运用其自己的分享档案夹来管理它的开发程式, 不过事实并非如此. 那么, 它是如何做的呢?
- 有个主开发线, 此处存有稳定建置的Windows.
- 每一个功能群组(网路, 使用者介面, 多媒体播放器, 等等.) 有他们自己的分支发展他们各自的功能. 相较于主开发线这些分支为正在开发中且较不稳定的发展内容.
你在新功能的分支开发,然后用“Reverse Integrate (RI)” 并回主线. 之后, 你 “Forward Integrate”且从主线拿到最近的变更并入你的分支:

假设我们在 Media Player 10 和 IE 6. Media Player 团队在他们的分支做了version 11. 当其完成并通过测试, 产生从10到11的patch, 此被主线采用 (就像 “Rice” 的例子, 不过复杂些 ). 此为reverse integration, 从branch到trunk. IE团队也可同样执行.
之后, Media Player 团队可以取得其他团队最近更新的程式码, 如IE的. 如此, Media Player forward integrates 并从主线获得最近的patches整合回他们的branch. 这有点像之前的例子去拉主线的”Bread”到实验性的branch, 但, 也是比较复杂.
所以这就是所谓的RI和FI. 哼哼, 这样的安排可以让变更先在分支互相协调, 也同时让新的程式码不干扰主线的稳定度. 酷吧 ?
事实上, 可以有很多层次的分支和副分支, 配合品管度量来决定你何时要做RI. 不过要知道: 分支帮助您处理复杂度. 现在你知道一个大型的软体项目基本上是如何组织了吧.
重点提示
我的目标是分享有关版本控管系统的高阶想法. 以下为基础要点: :
- 使用版本控制. 认真告诉你,这是个好东西,就算你不是写OS那么大的东西. 就算单人用也值得.
- 从小处著手(Take it slow). 我也是现在才开始为我的项目了解如何做分支和合并. 才开始要运用这样的功能来管理. 如果你的项目还小, 分支和合并可能不是个问题. 维护大项目的人应该对分支和补丁的追踪很有经验了.
- 保持学习. 可以参考很多指引: SVN, CVS, RCS, Git, Perforce 或更多你正在使用的系统资料. 重要的是把观念搞清楚并意识到每个系统有它自己的行话和哲理. 也建议参考Eric Sink的 detailed version control guide.
以上是基础资料 — 随著时间我将分享我从做my projects学到的东西. 现在你已了解一般的版本控制系统(VCS),也可以看看 an illustrated guide to distributed version control (DVCS分布式版本控制系统图解说明).
译注: 如有兴趣了解简便安装与管理Subversion的工具, 欢迎参考 CodeBeamer+Subversion实务操作手册