版本库的创建和配置

创建一个 Subversion 版本库出乎寻常的简单。 Subversion 提供的svnadmin 工具,有一个执行这个功能的子命令。要建立一个新的版本库,只需要运行:

$ svnadmin create /path/to/repos

这个命令在目录/path/to/repos创建了一个新的版本库。这个新的版本库会以修订版本版本0开始其生命周期,里面除了最上层的根目录(/),什么都没有。刚开始,修订版本0有一个修订版本属性svn:date,设置为版本库创建的时间。

在 Subversion 1.1中,版本库默认使用Berkeley DB后端存储方式来创建。在以后的发行版中这个行为会被改变。不管怎样,存储类型可以使用--fs-type参数明确说明。:

$ svnadmin create --fs-type fsfs /path/to/repos
$ svnadmin create --fs-type bdb /path/to/other/repos

警告

不要在网络共享上创建Berkeley DB版本库—它不能存在于诸如NFS, AFS或Windows SMB的远程文件系统中,Berkeley 数据要求底层文件系统实现严格的POSIX锁定语义,几乎没有任何网络文件系统提供这些特性,假如你在网络共享上使用Berkeley DB,结果是不可预知的——许多错误可能会立刻发现,也有可能在几个月之后才能发现

假如你需要多台计算机来访问,你需要在网络共享上创建FSFS版本库,而不是Berkeley DB的版本库。或者更好的办法,你建立一个真正的服务进程(例如Apache或svnserve),把版本库放在服务器能访问到的本地文件系统中,以便能通过网络访问。详情请参看第 6 章 配置服务器

你可能已经注意到了,svnadmin命令的路径参数只是一个普通的文件系统路径,而不是一个svn客户端程序访问版本库时使用的URL。svnadminsvnlook都被认为是服务器端工具—它们在版本库所在的机器上使用,用来检查或修改版本库,不能通过网络来执行任务。一个Subversion的新手通常会犯的错误,就是试图将URL(甚至“本地file:路径)传给这两个程序。

所以,当你运行svnadmin create命令后,就会在运行目录创建一个崭新的Subversion版本库,让我们看一下在这个目录创建中创建了什么。

$ ls repos
conf/  dav/  db/  format  hooks/  locks/  README.txt

除了README.txtformat文件,版本库目录就是一些子目录了。就像Subversion其它部分的设计一样,模块化是一个很重要的原则,而且层次化的组织要比杂乱无章好。下面是对新的版本库目录中各个项目的简要介绍:

conf

一个存储版本库配置文件的目录。

dav

提供给Apache和mod_dav_svn的目录,让它们存储自己的数据。

db

你所有的受版本控制数据的所在之处。这个目录或者是个Berkeley DB环境(满是数据表和其他东西),或者是一个包含修订版本文件的FSFS环境。

format

包含了用来表示版本库布局版本号的整数。

hooks

一个存储钩子脚本模版的目录(还有钩子脚本本身, 如果你安装了的话)。

locks

一个存储Subversion版本库锁定数据的目录,被用来追踪对版本库的访问。

README.txt

这个文件只是用来告诉它的阅读者,他现在看的是 Subversion 的版本库。

一般来说,你不需要手动干预版本库。svnadmin工具应该足以用来处理对版本库的任何修改,或者你也可以使用第三方工具(比如Berkeley DB的工具包)来调整部分版本库。不过还是会有些例外情况,我们会在这里提到。

钩子脚本

所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化属性的修改。每个钩子都会被告知足够多的信息,包括那是什么事件,所操作的对象,和触发事件的用户名。通过钩子的输出或返回状态,钩子程序能让工作继续、停止或是以某种方式挂起。

默认情况下,钩子的子目录中包含各种版本库钩子模板。

$ ls repos/hooks/
post-commit.tmpl          pre-revprop-change.tmpl
post-revprop-change.tmpl  start-commit.tmpl
pre-commit.tmpl           

对每种Subversion版本库支持的钩子的都有一个模板,通过查看这些脚本的内容,你能看到是什么事件触发了脚本及如何给传脚本传递数据。同时,这些模版也是如何使用这些脚本,结合Subversion支持的工具来完成有用任务的例子。要实际安装一个可用的钩子,你需要在repos/hooks目录下安装一些与钩子同名(如 start-commit或者post-commit)的可执行程序或脚本。

在Unix平台上,这意味着要提供一个与钩子同名的脚本或程序(可能是shell 脚本,Python 程序,编译过的c语言二进制文件或其他东西)。当然,脚本模板文件不仅仅是展示了一些信息—在Unix下安装钩子最简单的办法就是拷贝这些模板,并且去掉.tmpl扩展名,然后自定义钩子的内容,确定脚本是可运行的。Windows用文件的扩展名来决定一个程序是否可运行,所以你要使程序的基本名与钩子同名,同时,它的扩展名是Windows系统所能辨认的,例如execom和批处理的bat

提示

由于安全原因,Subversion版本库在一个空环境中执行钩子脚本—就是没有任何环境变量,甚至没有$PATH%PATH%。由于这个原因,许多管理员会感到很困惑,它们的钩子脚本手工运行时正常,可在Subversion中却不能运行。要注意,必须在你的钩子中设置好环境变量或为你的程序指定好绝对路径。

目前Subversion有已实现了五种钩子:

start-commit

它在提交事务产生前已运行,通常用来判定一个用户是否有权提交。版本库传给该程序两个参数:到版本库的路径,和要进行提交的用户名。如果程序返回一个非零值,会在事务产生前停止该提交操作。如果钩子程序要在stderr中写入数据,它将排队送至客户端。

pre-commit

在事务完成提交之前运行,通常这个钩子是用来保护因为内容或位置(例如,你要求所有到一个特定分支的提交必须包括一个bug追踪的ticket号,或者是要求日志信息不为空)而不允许的提交。版本库传递两个参数到程序:版本库的路径和正在提交的事务名称,如果程序返回非零值,提交会失败,事务也会删除。如果钩子程序在stderr中写入了数据,也会传递到客户端。

Subversion的分发版本包括了一些访问控制脚本(在Subversion源文件目录树的tools/hook-scripts目录),可以用来被pre-commit调用来实现精密的写访问控制。另一个选择是使用Apache的httpd模块mod_authz_svn,可以对单个目录进行读写访问控制(见“每目录访问控制”一节)。在未来的Subversion版本中,我们计划直接在文件系统中实现访问控制列表(ACLs)。

post-commit

它在事务完成后运行,创建一个新的修订版本。大多数人用这个钩子来发送关于提交的描述性电子邮件,或者作为版本库的备份。版本库传给程序两个参数:到版本库的路径和被创建的新的修订版本号。退出程序会被忽略。

Subversion分发版本中包括mailer.pycommit-email.pl脚本(存于Subversion源代码树中的tools/hook-scripts/目录中)可以用来发送描述给定提交的email(并且或只是追加到一个日志文件),这个mail包含变化的路径清单,提交的日志信息、日期和作者以及修改文件的GNU区别样式输出。

Subversion提供的另一个有用的工具是hot-backup.py脚本(在Subversion源代码树中的tools/backup/目录中)。这个脚本可以为Subversion版本库进行热备份(Berkeley DB数据库后端支持的一种特性),可以制作版本库每次提交的快照作为归档和紧急情况的备份。

pre-revprop-change

因为Subversion的修订版本属性不是版本化的,对这类属性的修改(例如提交日志属性svn:log)将会永久覆盖以前的属性值。因为数据在此可能丢失,所以Subversion提供了这种钩子(及与之对应的post-revprop-change),因此版本库管理员可用一些外部方法记录变化。作为对丢失未版本化属性数据的防范,Subversion客户端不能远程修改修订版本属性,除非为你的版本库实现这个钩子。

这个钩子在对版本库进行这种修改时才会运行,版本库给钩子传递四个参数:到版本库的路径,要修改属性的修订版本,经过认证的用户名和属性自身的名字。

post-revprop-change

我们在前面提到过,这个钩子与pre-revprop-change对应。事实上,因为多疑的原因,只有存在pre-revprop-change时这个脚本才会执行。当这两个钩子都存在时,post-revprop-change在修订版本属性被改变之后运行,通常用来发送包含新属性的email。版本库传递四个参数给该钩子:到版本库的路径,属性存在的修订版本,经过校验的产生变化的用户名,和属性自身的名字。

Subversion分发版本中包含propchange-email.pl脚本(在Subversion源代码树中的tools/hook-scripts/目录中),可以用来发送修订版本属性修改细节的email(并且或只是追加到一个日志文件)。这个email包含修订版本和发生变化的属性名,作出修改的用户和新属性值。

警告

不要尝试用钩子脚本修改事务。一个常见的例子就是在提交时自动设置svn:eol-stylesvn:mime-type这类属性。这看起来是个好主意,但它会引起问题。主要的问题是客户并不知道由钩子脚本进行的修改,同时没有办法通告客户它的数据是过时的,这种矛盾会导致出人意料和不能预测的行为。

作为尝试修改事务的替代,我们通过检查pre-commit钩子的事务,在不满足要求时拒绝提交。

Subversion会试图以当前访问版本库的用户身份执行钩子。通常,对版本库的访问总是通过Apache HTTP服务器和mod_dav_svn进行,因此,执行钩子的用户就是运行Apache的用户。钩子本身需要具有操作系统级的访问许可,用户可以运行它。另外,其它被钩子直接或间接使用的文件或程序(包括Subversion版本库本身)也要被同一个用户访问。换句话说,要注意潜在的访问控制问题,它可能会让你的钩子无法按照你的目的顺利执行。

Berkeley DB配置

Berkeley DB环境是对一个或多个数据库、日志文件、区域文件和配置文件的封装。Berkeley DB环境对许多参数有自己的缺省值,例如任何时间里可用的锁定数目、日志文件的最大值等。Subversion文件系统会使用Berkeley DB的默认值。 不过,有时候你的特定版本库与它独特的数据集合和访问类型,可能需要不同的配置选项。

Sleepycat(Berkeley DB的制造厂商)的人们清楚不同的数据库有不同的需求,所以他们提供了在运行中覆盖Berkeley DB环境配置参数的机制。Berkeley在每一个环境目录中检查是否存在一个名叫DB_CONFIG的文件,然后解析其中的参数成为Berkeley环境所用的选项。

你的版本库的Berkeley配置文件位于db目录的repos/db/DB_CONFIG, Subversion在创建版本库时自己创建了这个文件。这个文件初始时包含了一些默认选项,也包含了Berkeley DB在线文档,使你能够了解这些选项是做什么的。当然,你也可以为你的DB_CONFIG 文件添加任何Berkeley DB支持的选项。需要注意到,虽然Subversion不会尝试读取并解析这个文件,或使用其中的设置,你一定要避免会导致Berkeley DB按照Subversion代码不习惯的方式工作的修改。另外,DB_CONFIG的修改在复原数据库环境(用svnadmin recover)之前不会产生任何效果。