本手册撰写时基于 Subversion 1.1 版本。如果您使用的是更新版本的 Subversion,强烈建议您访问 https://svnbooks.subversion.org.cn/ 并查阅适合您 Subversion 版本的书籍。
创建 Subversion 仓库是一项非常简单的任务。Subversion 提供的 svnadmin 工具有一个子命令可以完成这项工作。要创建新的仓库,只需运行
$ svnadmin create /path/to/repos
这将在目录中创建新的仓库/path/to/repos。这个新的仓库从版本 0 开始,版本 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 DB 要求底层文件系统实现严格的 POSIX 锁定语义,更重要的是,能够将文件直接映射到进程内存中。几乎没有网络文件系统提供这些功能。如果您尝试在网络共享上使用 Berkeley DB,结果是不可预测的——您可能会立即看到神秘的错误,或者在几个月后才发现您的仓库数据库已 subtly 损坏。
如果您需要多台计算机访问仓库,您可以在网络共享上创建一个 FSFS 仓库,而不是 Berkeley DB 仓库。或者更好的是,设置一个真正的服务器进程(如 Apache 或 svnserve),将仓库存储在服务器可以访问的本地文件系统上,并通过网络提供仓库。 第 6 章,服务器配置 详细介绍了此过程。
您可能已经注意到,svnadmin 的路径参数只是一个常规的文件系统路径,而不是像 svn 客户端程序在引用仓库时使用的 URL。svnadmin 和 svnlook 被认为是服务器端工具——它们用于在仓库所在的机器上检查或修改仓库的某些方面,实际上无法跨网络执行任务。Subversion 新手常犯的一个错误是试图将 URL(即使是“本地”文件”) 传递给这两个程序。
因此,在运行 svnadmin create 命令之后,您就在其自己的目录中拥有了一个闪亮的新 Subversion 仓库。让我们看看在该子目录中实际创建了什么。
$ ls repos conf/ dav/ db/ format hooks/ locks/ README.txt
除了README.txt和format文件之外,仓库目录是子目录的集合。与 Subversion 设计的其他方面一样,模块化受到高度重视,并且优先采用分层组织,而不是杂乱无章。以下是您在新的仓库目录中看到的所有项目的简要说明
包含仓库配置文件的目录。
为 Apache 和 mod_dav_svn 提供的目录,用于存储其私有管理数据。
所有版本化数据所在的目录。此目录要么是 Berkeley DB 环境(包含许多 DB 表和其他内容),要么是包含版本文件的 FSFS 环境。
一个文件,其内容是一个单整数值,指示仓库布局的版本号。
一个包含挂钩脚本模板(以及安装后的挂钩脚本本身)的目录。
Subversion 仓库锁定数据的目录,用于跟踪仓库的访问者。
一个文件,它只是告知读者他们正在查看 Subversion 仓库。
一般来说,您不应该“手动”修改仓库。svnadmin 工具应该足以对仓库进行任何必要的更改,或者您可以使用第三方工具(如 Berkeley DB 的工具套件)来调整仓库的相关部分。但有一些例外情况,我们将在下面介绍。
一个 挂钩 是一个由某些仓库事件触发的程序,例如创建新的版本或修改未版本化的属性。每个挂钩都会接收足够的信息来告知该事件是什么,它操作的目标是什么,以及触发该事件的用户的用户名。根据挂钩的输出或返回值,挂钩程序可以继续执行该操作,停止它或以某种方式暂停它。
该hooks子目录默认情况下包含各种仓库挂钩的模板。
$ 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 为可执行程序识别的特殊扩展名之一,例如.exe或.com用于程序,以及.bat用于批处理文件。
出于安全原因,Subversion 仓库会使用空环境执行挂钩脚本——也就是说,根本不设置任何环境变量,甚至不设置$PATH或%PATH%。因此,许多管理员对他们的挂钩脚本手动运行正常,但由 Subversion 运行时却无法正常工作感到困惑。请务必在挂钩中显式设置环境变量,或使用程序的绝对路径。
目前 Subversion 仓库实现了五个挂钩
在创建提交事务之前运行。它通常用于确定用户是否具有提交权限。仓库向此程序传递两个参数:仓库的路径和尝试提交的用户名。如果程序返回非零退出值,则在创建事务之前停止提交。如果挂钩程序向 stderr 写入数据,则会将数据传回客户端。
在事务完成但提交之前运行。通常,此挂钩用于防止由于内容或位置而被禁止的提交(例如,您的站点可能要求对特定分支的所有提交都包含来自错误跟踪器的工单号,或者要求传入的日志消息不为空)。仓库向此程序传递两个参数:仓库的路径和正在提交的事务的名称。如果程序返回非零退出值,则中止提交并删除事务。如果挂钩程序向 stderr 写入数据,则会将数据传回客户端。
Subversion 发行版中包含一些访问控制脚本(位于 Subversion 源代码树的tools/hook-scripts目录中),这些脚本可以从 pre-commit 调用,以实现细粒度的写访问控制。另一种选择是使用 mod_authz_svn Apache httpd 模块,该模块提供对单个目录的读写访问控制(参见 名为“按目录访问控制”的部分)。在 Subversion 的未来版本中,我们计划直接在文件系统中实现访问控制列表 (ACL)。
在事务提交并创建新的版本之后运行。大多数人使用此挂钩来发送有关提交的描述性电子邮件或备份仓库。仓库向此程序传递两个参数:仓库的路径和创建的新版本号。程序的退出代码将被忽略。
Subversion 发行版中包含 mailer.py 和 commit-email.pl 脚本(位于 Subversion 源代码树的tools/hook-scripts/目录中),这些脚本可用于发送电子邮件(或将信息追加到日志文件),其中包含对给定提交的描述。此邮件包含已更改的路径列表、附加到提交的日志消息、提交的作者和日期,以及对提交过程中对各种版本化文件所做的更改的 GNU diff 风格的显示。
Subversion 提供的另一个有用工具是 hot-backup.py 脚本(位于 Subversion 源代码树的tools/backup/目录中)。此脚本执行 Subversion 仓库的热备份(Berkeley DB 数据库后端支持此功能),可用于为存档或紧急恢复目的制作仓库的每次提交快照。
因为 Subversion 的版本属性不是版本化的,所以对属性进行修改(例如,svn:log提交消息属性)将永远覆盖该属性的先前值。由于在这里可能会丢失数据,Subversion 提供了此挂钩(及其对应项,post-revprop-change),以便仓库管理员可以根据需要使用某些外部手段记录对这些项目的更改。作为防止丢失未版本化属性数据的预防措施,Subversion 客户端将不被允许远程修改版本属性,除非您的仓库实现了此挂钩。
此挂钩在对仓库进行此类修改之前运行。仓库向此挂钩传递四个参数:仓库的路径、要修改的属性所在的版本、进行更改的经过身份验证的用户名以及属性本身的名称。
如前所述,此挂钩是pre-revprop-change挂钩的对应项。实际上,为了安全起见,除非存在pre-revprop-change挂钩,否则此脚本将不会运行。当这两个挂钩都存在时,post-revprop-change挂钩在修改版本属性之后运行,通常用于发送包含已更改属性的新值的电子邮件。仓库向此挂钩传递四个参数:仓库的路径、属性所在的版本、进行更改的经过身份验证的用户名以及属性本身的名称。
Subversion 发行版中包含一个 propchange-email.pl 脚本(位于 Subversion 源代码树的tools/hook-scripts/目录中),该脚本可用于发送电子邮件(或将信息追加到日志文件),其中包含版本属性更改的详细信息。此邮件包含已更改属性的版本和名称、进行更改的用户以及新的属性值。
不要尝试使用挂钩脚本修改事务。一个常见的例子是自动设置属性,例如svn:eol-style或svn:mime-type在提交期间。虽然这看起来是个好主意,但它会导致问题。主要问题是客户端不知道挂钩脚本所做的更改,并且无法通知客户端它已过时。这种不一致会导致令人惊讶和意外的行为。
与其尝试修改事务,不如在pre-commit挂钩中检查事务,如果不满足所需的要求,则拒绝提交。
Subversion 将尝试以与访问 Subversion 存储库的进程相同的用户身份执行挂钩。在大多数情况下,存储库是通过 Apache HTTP 服务器和 mod_dav_svn 访问的,因此此用户与 Apache 运行的用户相同。挂钩本身需要配置 OS 级别的权限,允许该用户执行它们。此外,这意味着挂钩直接或间接访问的任何文件或程序(包括 Subversion 存储库本身)都将以相同用户身份访问。换句话说,请注意可能阻止挂钩执行您编写其执行的任务的潜在权限相关问题。
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 在线文档的指针,以便您可以阅读这些选项的作用。当然,您可以随意将任何支持的 Berkeley DB 选项添加到您的DB_CONFIG文件中。请注意,虽然 Subversion 从未尝试读取或解释文件的内容,并且没有使用其中的选项设置,但您需要避免任何可能导致 Berkeley DB 以 Subversion 代码其余部分意外的方式运行的配置更改。此外,对DB_CONFIG的更改将不会生效,直到您恢复数据库环境(使用 svnadmin recover)。