第 1 章 基本概念
记住Subversion可以管理任何类型的文件集—-----它并非是程序员专用的。
版本库是Subversion的核心部分,是数据的中央仓库。Subversion是一个“集中式”的信息共享系统.
版本库以典型的文件和目录结构形式 文件系统树 来保存信息。
Subversion听起来和一般的文件服务器没什么不同。事实上,Subversion的版本库的确_是_一种文件服务器,但不是“一般”的文件服务器。Subversion版本库的特别之处在于,_它会记录每一次改变_:每个文件的改变,甚至是目录树本身的改变,例如文件和目录的添加、删除和重新组织。
_版本控制系统_的核心问题:设计用来记录和跟踪数据变化的系统。
版本模型
版本控制系统的核心任务是 实现协作编辑和数据共享,但是不同的系统使用 不 同的策略实现这个目的。
Subversion本身支持不同的工作方式。
文件共享的问题
我们有两个共同工作者,Harry和Sally,他们想同时编辑版本库里的同一个文件,如果首先Harry保存它的修改,过了一会,Sally可能凑巧用自己的版本覆盖了这些文件,Harry的更改不会永远消失(因为系统记录了每次修改),但Harry所有的修改_不会_出现在Sally新版本的文件中,所以Harry的工作还是丢失了—至少是从最新的版本中丢失了—而且可能是意外的,这就是我们要明确避免的情况!
锁定-修改-解锁 方案
许多版本控制系统使用_锁定-修改-解锁_机制解决这种问题,在这样的模型里,在一个时间段里版本库的一个文件只允许被一个人修改。首先在修改之前,Harry要“锁定”住这个文件,锁定很像是从图书馆借一本书,如果Harry锁住这个文件,Sally不能做任何修改,如果Sally想请求得到一个锁,版本库会拒绝这个请求。在Harry结束编辑并且放开这个锁之前,她只可以阅读文件。Harry解锁后,就要换班了,Sally得到自己的轮换位置,锁定并且开始编辑这个文件。
锁定-修改-解锁模型有一点问题就是限制太多,经常会成为用户的障碍:
_锁定可能导致管理问题。_有时候Harry会锁住文件然后忘了此事,这就是说Sally一直等待解锁来编辑这些文件,她在这里僵住了。然后Harry去旅行了,现在Sally只好去找管理员放开锁,这种情况会导致不必要的耽搁和时间浪费。
_锁定可能导致不必要的线性化开发。_如果Harry编辑一个文件的开始,Sally想编辑同一个文件的结尾,这种修改不会冲突,设想修改可以正确的合并到一起,他们可以轻松的并行工作而没有太多的坏处,没有必要让他们轮流工作。
_锁定可能导致错误的安全状态。_假设Harry锁定和编辑一个文件A,同时Sally锁定并编辑文件B,如果A和B互相依赖,这种变化是必须同时作的,这样A和B不能正确的工作了,锁定机制对防止此类问题将无能为力—从而产生了一种处于安全状态的假相。很容易想象Harry和Sally都以为自己锁住了文件,而且从一个安全,孤立的情况开始工作,因而没有尽早发现他们不匹配的修改。锁定经常成为真正交流的替代品
拷贝-修改-合并 方案
Subversion,CVS和一些版本控制系统使用_拷贝-修改-合并_模型,在这种模型里,每一个客户联系项目版本库建立一个个人_工作拷贝_—版本库中文件和目录的本地映射。用户并行工作,修改各自的工作拷贝,最终,各个私有的拷贝合并在一起,成为最终的版本,这种系统通常可以辅助合并操作,但是最终要靠人工去确定正误。
拷贝-修改-合并模型感觉有一点混乱,但在实践中,通常运行的很平稳,用户可以并行的工作,不必等待别人,当工作在同一个文件上时,也很少会有交迭发生,冲突并不频繁,处理冲突的时间远比等待解锁花费的时间少。
最后,一切都要归结到一条重要的因素:用户交流。当用户交流贫乏,语法和语义的冲突就会增加,没有系统可以强制用户完美的交流,没有系统可以检测语义上的冲突,所以没有任何证据能够承诺锁定系统可以防止冲突,实践中,锁定除了约束了生产力,并没有做什么事。
什么时候锁定是必需的
锁定-修改-解锁模型被认为不利于协作,但有时候锁定会更好。
拷贝-修改-合并模型假定文件是可以根据上下文合并的:就是版本库的文件主要是以行为基础的文本文件(例如程序源代码)。但对于二进制格式,例如艺术品或声音,在这种情况下,十分有必要让用户轮流修改文件,如果没有线性的访问,有些人的许多工作就最终要被放弃。
尽管Subversion一直主要是一个拷贝-修改-合并系统,但是它也意识到了需要锁定一些文件,并且提供这种锁定机制,
Subversion实践
Subversion版本库URL
svn checkout http://svn.example.com:9834/repos
svn checkout file://localhost/path/to/repos
C:\> svn checkout file:///X:/path/to/repos
…
C:\> svn checkout "file:///X|/path/to/repos"
…
$ svn checkout "http://host/path with space/project/españa"
…Subversion会回避这些不安全字符,并且会像你输入了这些字符一样工作:
$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a
如果URL包含空格,一定要使用引号,这样你的脚本才会把它做一个单独的svn参数
工作拷贝
一个典型的Subversion的版本库经常包含许多项目的文件(或者说源代码),通常每一个项目都是版本库的子目录,在这种布局下,一个用户的工作拷贝往往对应 版本库 的的一个子目录。
为了得到一个工作拷贝,你必须_检出_(_check out_)版本库的一个子树,(术语“check out”听起来像是锁定或者保留资源,实际上不是,只是简单的得到一个项目的私有拷贝),举个例子,你检出 /calc
,你可以得到这样的工作拷贝:
$ svn checkout http://svn.example.com/repos/calc
A calc/Makefile
A calc/integer.c
A calc/button.c
Checked out revision 56.
$ ls -A calc
Makefile integer.c button.c .svn/
列表中的A表示Subversion增加了一些条目到工作拷贝,你现在有了一个/calc
的个人拷贝,有一个附加的目录—.svn
—保存着前面提及的Subversion需要的额外信息。
假定你修改了button.c
,因为.svn
目录记录着文件的修改日期和原始内容,Subversion可以告诉你已经修改了文件,然而,在你明确告诉它之前,Subversion不会将你的改变公开,将改变公开的操作被叫做提交(_committing_,或者是_checking in_)修改到版本库。
将你的修改发布给别人,你可以使用Subversion的提交(commit)命令。
$ svn commit button.c -m "Fixed a typo in button.c."
Sending button.c
Transmitting file data .
Committed revision 57.
$ pwd
/home/sally/calc
$ ls -A
.svn/ Makefile integer.c button.c
$ svn update
U button.c
Updated to revision 57.
svn update命令的输出表明Subversion更新了button.c
的内容,注意,Sally不必指定要更新的文件,subversion利用.svn
以及版本库的进一步信息决定哪些文件需要更新。
Subversion可以通过多种方式访问—本地磁盘访问,或各种各样不同的网络协议,这要看你的管理员是如何设置,但一个版本库地址永远都只是一个URL
Subversion的修订号是针对整个_目录树_的,而不是单个文件。每一个修订号代表了一次提交后版本库整个目录树的特定状态,另一种理解是修订号N代表版本库已经经过了N次提交。当Subversion用户讨论“foo.c
的修订号5”时,他们的实际意思是“在修订号5时的foo.c
”。需要注意的是,一个文件的修订版本N和M并_不必_有所不同。许多其它版本控制系统使用每文件一个修订号的策略,所以会感觉这些概念有点不一样。(以前的CVS用户可能希望察看附录 B, _CVS用户的Subversion指南_来得到更多细节。)