本手册是为描述 Subversion 1.2 而编写的。如果您运行的是更新版本的 Subversion,我们强烈建议您访问 https://svnbooks.subversion.org.cn/ 并查阅适合您 Subversion 版本的版本。
创建 Subversion 仓库是一项非常简单的任务。Subversion 附带的 svnadmin 实用程序有一个用于执行此操作的子命令。要创建新的仓库,只需运行
$ svnadmin create /path/to/repos
这将在目录 /path/to/repos
中创建一个新的仓库。这个新的仓库从修订版 0 开始,定义为仅包含顶层根目录 (/
) 文件系统目录。最初,修订版 0 还包含一个唯一的修订版属性 svn:date
,设置为创建仓库的时间。
在 Subversion 1.2 中,仓库默认使用 FSFS 后端创建(参见 名为“仓库数据存储”的部分)。后端可以使用 --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,结果是不可预测的——您可能会立即看到神秘的错误,或者几个月后才会发现您的仓库数据库发生了细微的损坏。
如果您需要多台计算机访问仓库,请在网络共享上创建 FSFS 仓库,而不是 Berkeley DB 仓库。或者更好的方法是,设置一个真正的服务器进程(例如 Apache 或 svnserve),将仓库存储在服务器可以访问的本地文件系统上,并将仓库通过网络提供。第 6 章,服务器配置 详细介绍了此过程。
您可能已经注意到,传递给 svnadmin 的路径参数只是一个普通的文件系统路径,而不是像 svn 客户端程序在引用仓库时使用的 URL。 svnadmin 和 svnlook 被认为是服务器端实用程序——它们用于仓库所在的机器上检查或修改仓库的各个方面,实际上无法跨网络执行任务。Subversion 新手常犯的一个错误是尝试将 URL(即使是“本地” file:
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 post-unlock.tmpl pre-revprop-change.tmpl post-lock.tmpl pre-commit.tmpl pre-unlock.tmpl post-revprop-change.tmpl pre-lock.tmpl start-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 仓库实现了 9 个钩子
start-commit
在创建提交事务之前运行。它通常用于决定用户是否拥有提交权限。仓库将两个参数传递给该程序:仓库的路径和尝试提交的用户名的路径。如果程序返回非零退出值,则提交在创建事务之前停止。如果钩子程序将数据写入 stderr,则该数据将被传递回客户端。
pre-commit
在事务完成但尚未提交之前运行。通常,此钩子用于防止由于内容或位置而被禁止的提交(例如,您的站点可能要求对某个分支的所有提交都包含来自错误跟踪器的票证号,或者要求传入的日志消息不能为空)。仓库将两个参数传递给该程序:仓库的路径和要提交的事务的名称。如果程序返回非零退出值,则提交被中止,并且事务被删除。如果钩子程序将数据写入 stderr,则该数据将被传递回客户端。
Subversion 分发版包含一些访问控制脚本(位于 Subversion 源代码树的 tools/hook-scripts
目录中),可以从 pre-commit 中调用它们来实现细粒度的写访问控制。另一个选择是使用 mod_authz_svn Apache httpd 模块,该模块提供对各个目录的读写访问控制(参见 名为“每个目录访问控制”的部分)。在 Subversion 的未来版本中,我们计划在文件系统中直接实现访问控制列表(ACL)。
post-commit
在提交事务并创建新的修订版之后运行。大多数人使用此钩子发送有关提交的描述性电子邮件或备份仓库。仓库将两个参数传递给该程序:仓库的路径和创建的新的修订版号。程序的退出代码被忽略。
Subversion 分发版包含 mailer.py 和 commit-email.pl 脚本(位于 Subversion 源代码树的 tools/hook-scripts/
目录中),可用于发送包含(或追加到日志文件)给定提交描述的电子邮件。此邮件包含已更改的路径列表、附加到提交的日志消息、提交的作者和日期,以及对作为提交的一部分对各种版本化文件进行的更改的 GNU diff 样式显示。
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
钩子将在修改修订版属性之后立即运行,通常用于发送包含已更改属性的新值的电子邮件。仓库将四个参数传递给此钩子:仓库的路径、属性所在的修订版、进行更改的经过身份验证的用户名以及属性本身的名称。
Subversion 发行版包含一个 propchange-email.pl 脚本(位于 Subversion 源代码树的 tools/hook-scripts/
目录中),可用于发送包含(或追加到日志文件)版本属性更改详细信息的电子邮件。此邮件包含更改的属性的版本和名称、进行更改的用户以及新的属性值。
pre-lock
此钩子在有人尝试锁定文件时运行。它可以用来完全阻止锁定,或者创建一个更复杂的策略,明确规定哪些用户可以锁定特定路径。如果钩子注意到预先存在的锁定,那么它也可以决定用户是否可以“窃取”现有锁定。存储库向钩子传递三个参数:存储库的路径、正在锁定的路径以及尝试执行锁定的用户。如果程序返回非零退出值,则锁定操作将中止,任何打印到 stderr 的内容都将被传回客户端。
post-lock
此钩子在路径被锁定后运行。锁定的路径被传递到钩子的 stdin,钩子还接收两个参数:存储库的路径以及执行锁定的用户。然后,钩子可以自由地发送电子邮件通知或以任何方式记录事件。由于锁定已经发生,因此会忽略钩子的输出。
pre-unlock
此钩子在有人尝试从文件上删除锁定时运行。它可以用来创建策略,明确规定哪些用户可以解锁特定路径。对于确定有关锁定中断的策略尤其重要。如果用户 A 锁定了一个文件,用户 B 是否可以打破锁定?如果锁定时间超过一周,会怎么样?这些事情可以通过钩子来决定和执行。存储库向钩子传递三个参数:存储库的路径、正在解锁的路径以及尝试删除锁定的用户。如果程序返回非零退出值,则解锁操作将中止,任何打印到 stderr 的内容都将被传回客户端。
post-unlock
此钩子在路径被解锁后运行。解锁的路径被传递到钩子的 stdin,钩子还接收两个参数:存储库的路径以及删除锁定的用户。然后,钩子可以自由地发送电子邮件通知或以任何方式记录事件。由于锁定已移除,因此会忽略钩子的输出。
不要尝试使用钩子脚本修改事务。一个常见的例子是,在提交期间自动设置属性,例如 svn:eol-style
或 svn:mime-type
。虽然这似乎是一个好主意,但它会导致问题。主要问题是客户端不知道钩子脚本所做的更改,并且没有办法通知客户端它已过期。这种不一致会导致意外和意外的行为。
与其尝试修改事务,不如在 pre-commit
钩子中 检查 事务,如果事务不符合所需要求,则拒绝提交。
Subversion 将尝试以与访问 Subversion 存储库的进程相同的用户身份执行钩子。在大多数情况下,存储库是通过 Apache HTTP 服务器和 mod_dav_svn 访问的,因此此用户与 Apache 运行的用户相同。钩子本身需要配置操作系统级别的权限,允许该用户执行它们。同样,这意味着任何由钩子直接或间接访问的文件或程序(包括 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)之前生效。