第一章 简 介 版本控制是管理信息变更的一门艺术。版本控制工具早已经成为许多程序员的主要工具之一,特别是那些时常对软件代码作了微小的改动却隔了一天就撤销的程序员们。但是版本控制软件的用途并不仅限于软件开发的领域。只要人们使用计算机来管理经常变更的信息,就需要使用版本控制工具。而这正是 Subversion 可以展示自己的地方。 本章是对 Subversion 的一个概括性的介绍:Subversion 是什么?它用来做什么?以及如何得到它。 1.1 什么是 Subversion? Subversion 是一个自由的、开放源码的版本控制系统。也就是说,它可以管理各个时刻的文件和目录。Subversion 将文件存放在一个中心仓库(repository)中。这个仓库非常类似于一个普通的文件服务器,只是它还可以记录文件和目录曾经做过的每一次变更。这样,我们就可以恢复旧版本中的数据或者是检查数据曾经做过怎样的改动。在这点上,许多人都将版本控制系统比作一种“时间机器”。 Subversion 的仓库可以通过网络来访问,允许不同的用户在不同的计算机上使用。而使不同的使用者能够在各自所在的位置修改和管理同一组数据将会在某种程度上促进协同工作。由于不再将所有的修改工作都限制在一个“通道”上,项目的前进将更快速。而且因为所作的工作都是被记录的,如果做出了什么错误的修改,只需要撤销就可以了,而不用担心失去那个“通道”将会同时失去质量。 有些版本控制工具同时还是软件配置管理系统(SCM,Software Configuration Management System)。这些系统是针对管理源代码二设计的。它们有许多针对软件开发的特性,例如本身就可以识别程序设计语言的语法,或者是提供编译软件的工具。然而,Subversion 并不是这样一个系统。它是一个通用的,可以管理任何计算机文件的系统。对你来说,可能是管理源代码,而对其他人来说,从购物清单到视频文件都是可能的。 1.2 Subversion 的历史 在2000年年初,CollabNet公司(http://www.collab.net)就开始寻找开发人员来设计一个用以替代 CVS 的系统。CollabNet 公司当时正在提供一种叫做“SourceCast”的软件协作开发套件。其中的一个组件就是版本控制系统。虽然该系统最初是使用 CVS 作为版本控制组件的,但是 CVS 的局限性从从始至终就很明显。CollabNet 公司知道自己最终必须找到一个更好的替代品。但是很不幸,CVS 已经成为了开放源码领域中的事实上的标准。而很大一部分原因是因为找不到其他更好的系统。至少找不到更好的自由软件。于是,CollabNet 公司决定从头设计一个版本控制系统。一个保留了 CVS 的基本思想,但是却没有缺陷的、有特色的版本控制系统。 2000年二月,他们联系到了 Open Source Development with CVS 一书的作者 Karl Fogel。并且邀请其加入这个新项目。很巧合的是,那时 Karl 已经和他的朋友 Jim Blandy 讨论过一套新的版本控制系统的设计。在1995年,他们两人曾经开办过一家公司 Cyclic Software。公司专门提供对 CVS 的支持服务。虽然他们后来卖掉了这项业务,但是仍然在每天的工作中使用 CVS 。在 CVS 上的挫败让 Jim 得以仔细的思考管理版本化数据的更好的方法。他不仅提出了“Subversion”的名字,同时还构思了 Subversion 中心仓库 Repository 的基础设计思路。所以当 CollabNet 征招时,Karl 几乎立刻就答应了参加项目。Jim 的雇主:RedHat Software 赞助了该项目,并且是不限期的。CollabNet 雇用了 Karl 和 Ben Collins-Sussman。详细的设计工作从当年五月开始。这里我们应该提到 CollabNet 的 Brian Behlendorf 和 Jason Robbins 以及 Greg Stein (当时是活跃于 WebDAV/DeltaV 规范进程的独立开发者)。在他们的努力下,Subversion 很快就吸引了一批活跃的开发者。这正说明了许多人也曾在使用 CVS 中有过受挫折的经历。并且希望能够改变这种局面。 最初的设计团队决定了一些简单的目标。他们并不想在版本控制方法学中开辟新的天地,而是去修改 CVS。他们让 Subversion 来使用 CVS 的特性,并且保留相同的开发模型。但是他们将避开 CVS 的那些明显的缺陷。尽管 Subversion 并不需要设计的像一个 CVS 的潜移默化的替代品,它仍然应该设计的与 CVS 很像,以便于 CVS 的用户可以毫不费力的切换过来。 在经过十四个月的编码之后,Subversion 于2001年8月进入“自测”阶段。也就是说,Subversion 的开发者们停止使用 CVS 来管理 Subversion 的代码,而取而代之的是 Subversion 自己。 当 CollabNet 启动项目,并且资助很大一部分工作时(公司为一部分全职的开发人员支付薪水),Subversion 同时也像其他的开放源码项目那样运行。项目由一种鼓励知识精英的松散的、透明的规则所支配。CollabNet 的版权许可是完全遵从 Debian Free Software Guidelines 的。换句话说,任何人,如果他愿意的话,都可以自由的下载、修改和再次发行 Subversion;不需要从 CollabNet 或者任何人那里获得授权。 1.3 Subversion 的特色 当我们说起 Subversion 给版本控制系统领域带来什么特色时,最好是说说它对 CVS 的设计所作的改进。如果你不熟悉 CVS 的话,你可能不理解这里的某些特性。如果你对版本控制也不了解,最好去阅读一下第二章:基本概念。在第二章我们给出了对版本控制的一般性的介绍。 Subversion 的特性: 目录控制 CVS 只能跟踪单个文件的历史,而 Subversion 实现了一个“虚拟”的受控文件系统,可以跟踪整个目录的变更。 真正的版本历史 由于 CVS 只限于记录文件的版本信息,像文件复制、重命名这样的操作它就不支持了。而这些操作是会实实在在发生的,它们改变了所对应目录的内容。另外,在 CVS 中,如果你要用一个新文件来替换一个旧文件,并且两个文件名称相同的话,新文件将不得不继承旧文件的历史信息。即使是两个文件毫不相干也是这样。而在 Subversion 中,我们可以添加、删除、复制和重命名文件和目录。每一个新添加的文件都将拥有它自己的全新的历史信息。 原子化提交 一个变更集要么完整地被提交到仓库中,要么不做任何改变。这就允许开发人员把构造和提交修改当作一个逻辑上的整体来看。从而避免发生不完整地提交变更的情况。 受控元数据 每一个文件和目录都有一个与其对应的属性集。你可以创建和保存任何“键名/键值”对来辅助文件本身。而这些属性就像文件内容一样,也是受版本控制系统控制的。 可选的网络层 Subversion 仓库的存取是一个抽象概念,有利于其他人实现新的网络访问机制。Subversion 可以作为一个外部模块插入到 Apache HTTP 服务器中。这带给它在稳定性和互操作性方面的巨大优势。并且,Subversion 可以方便的利用 Apache 所提供的功能――身份认证、权限管理、数据压缩等等。还有一个更轻量级的、单独的 Subversion 服务器叫做 Subversion server process。它引入了一种自定义的协议,可以很容易的使用 SSH 来建立通道。 一致的数据处理 Subversion 使用一种二进制的比较算法来表示文件之间的区别。它在文本文件(可阅读的)和二进制文件(不可阅读的)上是没有区别的。两种类型的文件经过压缩后都同样的存放在仓库中,唯一的不同就是在网络上传输时的方法。 高效的分支和标记 分支和标记所带来的开销与项目的规模并没有直接的关系。Subversion 在创建分支和标记时使用类似“连接”的方式来复制项目。这样这些操作就只会耗费很少的通常是一个固定长度的时间。 扩展能力 Subversion 没有什么历史包袱;它是由一组设计良好的 APIs实现的,包含在 C 的共享库中。这使得它很容易维护。也很容易被其他应用程序或语言使用。 1.4 Subversion 的结构 图1.1,“Subversion 结构”描述了 Subversion 的一个很粗略的设计思路。 在系统的一端是存放着所有受控制数据的 Subversion 仓库。另一端是 Subversion 的客户端程序,管理着受控数据的一部分在本地的映射(称为“工作副本”)。在这两端之间,是通过各种仓库存取层(Repository Access,RA)的多条通道。这些通道中,有些要使用计算机网络,再通过用来访问 Subversion 仓库的服务器。而有些则完全绕过了网络,直接对仓库进行操作。 1.5 安装 Subversion Subversion 是建立在一个叫做 APR(the Apache Portable Runtime library)的可移植运行库之上的。这也就是说,Subversion 可以运行在任何 Apache 服务器可以运行的操作系统之上:Windows、Linux,各种类型的 BSD、Mac OS X,Netware 以及其他的系统。 获得 Subversion 的最简单的方法就是下载适合于你的操作系统的二进制软件包。Subversion 的站点(http://subversion.tigris.org)一般会有这样的下载连接。通常来说,使用 Microsoft 操作系统的用户都可以得到有图形界面的安装程序。如果你使用的是类似 Unix 的操作系统的话,可以使用合适的打包分发系统(RPMs,DEBs,the ports tree等等)来获取。 同时,我们也可以直接使用源代码来编译 Subversion 。首先从它的官方站点下载最新的源代码发布。然后将其解压缩,按照 INSTALL 文件中的指示来编译系统。值得注意的是,一个发行版的源代码包中包含了许多工具,足够你编译出一个可以和远程仓库连接的命令行工具(一般来说,有 apr、apr-util和一个初始的库)。但是 Subversion 中一些可选的部分则需要许多其他软件支持,例如 Berkeley DB 或者 Apache 。如果你要编译一个完全的系统的话,必须保证拥有 INSTALL 文件中提到的所有的软件包。而如果你想使用 Subversion 本身来获取代码的话,可以用你的客户端程序来得到最实时的源代码。在“获取源代码”一节中,我们将详细介绍有关情况。 1.6 Subversion 的组件 一旦 Subversion 成功安装,我们将会看到多个不同的应用程序。下面我们就来大致的看一下都有些什么组件。如果下面的这些简要说明让您感到迷惑的话,请先别着急。这本书还有许多页是专门为您消除这些困惑的。 svn 一个命令行式的客户端程序; svnversion 报告本地工作副本状态(用当前档案的修订版本号表示)的程序; svnadmin 用来创建、tweaking或者是修复仓库的工具; svndumpfilter A program for filtering Subversion repository dumpfile format streams. mod_dav_svn Apache 服务器的一个插件模块,用来使其他人可以通过网络访问这个仓库; svnserve 一个定制的、独立的 Subversion 服务程序。可作为一个驻留进程运行或者是由 SSH 调用。是使仓库可以被别人通过网络访问的另一种方法。 假如你正确的安装了 Subversion ,你应该可以开始使用了。接下来的两章将为你介绍 Subversion 的命令行工具 svn 的使用。 1.7 快速入门 在我们当中,可能有些人不是很习惯从头到尾的阅读一本书来吸收新技术的方式。这一节,我们将先行给出一个 Subversion 的使用介绍。心急的读者可以有机会通过实践来学习使用 Subversion 的技巧。同时,我们会告诉你到哪一章节可以找到相关的东西。 如果你对版本控制的整体概念很生疏,或者对 CVS 和 Subversion 使用的“复制―修改―合并”模型不熟悉的话,最好在往下读之前先去仔细看一下第二章――基本概念。 注意: 在运行下面的例子之前,你必须保证下面两个工具可以正确运行: svn 命令行式的客户端程序; svnadmin 管理工具; 同时还必须保证你的 svn 工具是针对 Berkeley DB 编译的。可以运行 svn --version 然后检查 ra_local 模块是否可用来确认。如果没有这个模块,我们的客户端程序将无法访问 file://URLs 。 Subversion 将所有控制的数据都放在一个中央仓库中。所以首先,我们要创建一个这样的仓库: $ svnadmin create /path/to/repos $ ls /path/to/repos conf/ dav/ db/ format hooks/ locks/ README.txt 这个命令创建了一个包含 Subversion 仓库的目录 /path/to/repos 。另外,这个目录必须创建在本地磁盘,而不能是在网络共享磁盘上。该目录主要包含了一些 Berkeley DB 的文件。在这个目录中,你是找不到所保存的文件的。在第五章――仓库管理中可以找到更多的有关于仓库创建和维护的知识。 下一步,准备一个类似下面例子中的用来导入的文件、目录树。在树结构中,应该包含三个顶层目录:branches、tags 和 trunk。具体的原因后面便会清楚了(参见第四章――分支和合并)。 /tmp/project/branches/ /tmp/project/tags/ /tmp/project/trunk/ foo.c bar.c Makefile … 一旦你准备好了目录树,就可以使用 svn import 命令来导入数据到仓库中了(参见“svn import”一节): $ svn import /tmp/project file:///path/to/repos -m "initial import" Adding /tmp/project/branches Adding /tmp/project/tags Adding /tmp/project/trunk Adding /tmp/project/trunk/foo.c Adding /tmp/project/trunk/bar.c Adding /tmp/project/trunk/Makefile … Committed revision 1. $ 现在,仓库中就有了整个目录树中的数据。注意,原始的 /tmp/project 目录并没有变化,Subversion 并不使用它。(实际上,如果你愿意的话,可以删除该目录)。为了开始操作仓库中的数据,我们需要先创建一个数据的“工作副本(working copy)”出来。这类似于一种私有的工作区。向 Subversion “check out”(借出)一份仓库中 trunk 目录的工作副本: $ svn checkout file:///path/to/repos/trunk project A project/foo.c A project/bar.c A project/Makefile … Checked out revision 1. 现在,我们在一个新的 project 目录下就有了仓库中一部分数据的一个私人副本了。你可以在本地工作副本上编辑某个文件,然后再将那些修改提交到仓库中。 ・进入工作副本目录,修改文件内容; ・运行 svn diff 来检查你对文件的修改情况; ・运行 svn commit 来将新版本的文件提交到仓库中; ・运行 svn update 来使用仓库中最新的版本来更新你的本地工作副本。 如果想知道我们可以对“本地工作副本”所作的事情,请参阅第三章――使用指南。 这时,你可以选择是否让其他人通过网络访问你的仓库。你可以阅读第六章――服务器配置来学习不同的服务器程序和如何配置它们。