本文档正在编写中,可能会发生重大变化,可能无法准确描述 Apache™ Subversion® 软件的任何已发布版本。将此页面加入书签或以其他方式推荐给其他人可能不是一个明智的做法。请访问 https://svnbooks.subversion.org.cn/ 获取此书的稳定版本。

创建和配置您的版本库

本章前面(在 名为“版本库部署策略”的部分)中,我们讨论了在创建和配置 Subversion 版本库之前应做出的一些重要决定。现在,我们终于要动手了!在本节中,我们将了解如何实际创建一个 Subversion 版本库,以及如何配置它以在发生特殊版本库事件时执行自定义操作。

创建版本库

Subversion 版本库的创建是一项非常简单的任务。Subversion 附带的 svnadmin 实用程序提供了一个子命令 (svnadmin create) 用于执行此操作。

$ # Create a repository
$ svnadmin create /var/svn/repos
$

假设父目录 /var/svn 存在,并且您有足够的权限修改该目录,则前面的命令会在目录 /var/svn/repos 中创建一个新的版本库,并使用默认的文件系统数据存储 (FSFS)。您可以使用 --fs-type 参数显式选择文件系统类型,该参数接受 fsfsbdb 作为参数。

$ # Create an FSFS-backed repository
$ svnadmin create --fs-type fsfs /var/svn/repos
$
# Create a legacy Berkeley-DB-backed repository
$ svnadmin create --fs-type bdb /var/svn/repos
$

运行此简单命令后,您将拥有一个 Subversion 版本库。根据用户访问此新版本库的方式,您可能需要调整其文件系统权限。但由于基本的系统管理超出了本文的范围,因此我们将进一步探讨该主题作为读者的练习。

[Tip] 提示

svnadmin 的路径参数只是一个普通的文件系统路径,而不是 svn 客户端程序在引用版本库时使用的 URL。svnadminsvnlook 都被认为是服务器端实用程序——它们用于版本库所在的机器上检查或修改版本库的各个方面,实际上无法跨网络执行任务。Subversion 新手常犯的一个错误是尝试将 URL(即使是 本地 file:// URL)传递给这两个程序。

您的版本库的 db/ 子目录中包含版本化文件系统的实现。您的新版本库的版本化文件系统从修订版 0 开始,该修订版被定义为仅包含顶层根 (/) 目录。最初,修订版 0 还有一个唯一的修订版属性 svn:date,它设置为创建版本库的时间。

现在您已经有了版本库,是时候对其进行自定义了。

[Warning] 警告

虽然 Subversion 版本库的某些部分(例如配置文件和钩子脚本)旨在手动检查和修改,但您不应该(也不应该需要)手动 篡改版本库的其他部分。 svnadmin 工具应该足以满足您对版本库进行的任何必要更改,或者您可以寻求第三方工具来调整版本库的相关子部分。请不要尝试通过在版本库的数据存储文件进行探查来手动操作您的版本控制历史记录!

实现版本库钩子

一个 钩子 是由某些版本库事件触发的程序,例如创建新的修订版或修改未版本化的属性。某些钩子(所谓的 预钩子)在版本库操作之前运行,并提供一种方法来报告即将发生的事情,并完全阻止其发生。其他钩子(后钩子)在版本库事件完成后运行,对于执行检查(但不修改)版本库的任务很有用。每个钩子都会收到足够的信息来判断该事件是什么(或曾经是什么),提议的(或已完成的)特定版本库更改,以及触发该事件的用户的用户名。

默认情况下,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-commitpost-commit)执行。

在 Unix 平台上,这意味着提供一个脚本或程序(可以是 shell 脚本、Python 程序、编译的 C 二进制文件或其他许多东西),其名称与钩子的名称完全相同。当然,模板文件的存在不仅仅是为了提供信息——在 Unix 平台上安装钩子的最简单方法是简单地将相应的模板文件复制到一个不带 .tmpl 扩展名的新文件中,自定义钩子的内容,并确保脚本是可执行的。然而,Windows 使用文件扩展名来确定程序是否可执行,因此您需要提供一个程序,其基本名称是钩子的名称,其扩展名是 Windows 识别为可执行程序的特殊扩展名之一,例如 .exe 用于程序,.bat 用于批处理文件。

Subversion 以与拥有访问 Subversion 版本库的进程的用户相同的用户身份执行钩子。在大多数情况下,版本库是通过 Subversion 服务器访问的,因此此用户与服务器在系统上运行的用户相同。钩子本身需要使用操作系统级别的权限进行配置,以允许该用户执行它们。此外,这意味着钩子直接或间接访问的任何程序或文件(包括 Subversion 版本库)都将以相同用户的身份访问。换句话说,要注意可能阻止钩子执行其设计执行的任务的潜在权限相关问题。

Subversion 版本库实现了几种钩子,您可以在 Subversion 版本库钩子参考 中找到有关每种钩子的详细信息。作为版本库管理员,您需要决定要实现哪些钩子(通过提供一个命名和权限合适的钩子程序),以及如何实现。在做出此决定时,请牢记版本库的部署方式。例如,如果您使用服务器配置来确定允许哪些用户提交对版本库的更改,则无需通过钩子系统执行此类访问控制。

钩子脚本环境配置

默认情况下,Subversion 在空环境中执行钩子脚本,也就是说,根本没有设置环境变量,甚至没有设置 $PATH(或在 Windows 下的 %PATH%)。因此,许多管理员在手动运行钩子程序时一切正常,但在由 Subversion 调用时却无法工作,对此感到困惑。管理员通常通过在脚本本身中手动设置钩子脚本所需的所有环境变量来解决此问题。

Subversion 1.8 引入了一种管理 Subversion 执行的钩子脚本的环境的新方法——钩子脚本环境配置文件。如果 Subversion 服务器在版本库的 conf/ 子目录中找到名为 hooks-env 的文件,它会将该文件解析为 INI 格式的配置文件,并将其中找到的选项名称和变量作为环境变量应用于钩子脚本的执行环境。

hooks-env 文件的语法非常简单:每个节名都是一个钩子脚本的名称(例如 [pre-commit][post-revprop-change]),该节中的配置项被视为环境变量名称到所需值的映射。此外,还有一个特殊的 [default] 节,它可以用来配置应该应用于所有钩子脚本的环境变量映射(除非被每个钩子脚本设置显式覆盖)。请参阅 示例 5.1:“hooks-env(自定义钩子脚本环境配置)”,了解 hooks-env 配置文件的示例。

示例 5.1:hooks-env(自定义钩子脚本环境配置)

# All scripts should use a UTF-8 locale and have our hook script
# utilities directory on the search path.

[default]
LANG = en_US.UTF-8
PATH = /usr/local/svn/tools:/usr/bin


# The post-commit and post-revprop-change scripts want to run
# programs from our custom synctools replication software suite, too.

[post-commit]
PATH = /usr/local/synctools-1.1/bin:%(PATH)s

[post-revprop-change]
PATH = /usr/local/synctools-1.1/bin:%(PATH)s

[Note] 注意

示例 5.1:“hooks-env(自定义钩子脚本环境配置)” 还演示了 Subversion 配置文件解析器中找到的巧妙的字符串替换语法。在本例中,PATH 选项的值(从文件的 [default] 节中提取)被替换为每个钩子节中的 %(PATH)s 占位符文本。有关此特殊语法的更多信息,请参阅位于 Subversion 运行时配置目录中的 README.txt 文件。(有关该目录的更多信息,请参阅 名为“运行时配置区域”的部分。)

当然,在每个版本库的 conf/ 目录中都拥有自定义钩子脚本环境配置文件的精确副本可能会变得很麻烦,尤其是在您需要对它们进行更改时。因此,Subversion 的服务器允许您为该配置信息指定一个备用(可能是共享的)位置。

钩子脚本的常见用途

版本库钩子脚本可以提供广泛的实用程序,但大多数倾向于属于几个基本类别:通知、验证和复制。

通知脚本是告诉某人发生了某件事的脚本。在 Subversion 服务产品中发现的最常见的这类脚本包括通过 post-commit 和 post-revprop-change 钩子驱动,分别向项目成员发送提交和修订版属性更改通知电子邮件的程序。还有许多其他通知方法,从问题跟踪器集成脚本到充当 IRC 机器人以宣布版本库中发生了更改的脚本。

在验证方面,start-commit 和 pre-commit 钩子被广泛用于根据各种条件允许或拒绝提交:提交的作者、描述提交的日志消息的格式和/或内容,甚至提交对文件和目录所做的低级更改的详细信息。同样,pre-revprop-change 钩子充当修订版属性更改的门户,考虑到修订版属性本身不进行版本控制,因此只能以破坏性方式修改,因此这是一个特别有价值的角色。

自从 Subversion 1.5 发布以来,一种广泛应用的变更验证方法是验证提交客户端软件本身。当 Subversion 的合并跟踪功能(在 第 4 章,分支和合并 中有详细描述)在该版本中引入时,Subversion 管理员需要一种方法来确保一旦其存储库的用户开始使用新功能,所有 合并都会被跟踪。为了降低有人将未跟踪的合并提交到存储库的可能性,他们使用开始提交挂钩来检查 Subversion 客户端宣传的功能能力字符串。如果提交的客户端没有宣传支持合并跟踪,则会拒绝提交,并指示用户立即更新其 Subversion 客户端!示例 5.2,“要求合并跟踪支持的 start-commit 挂钩” 提供了一个执行此操作的 start-commit 脚本示例。

示例 5.2. 要求合并跟踪支持的 start-commit 挂钩

#!/usr/bin/env python
import sys

# sys.argv[3] is a colon-delimited capabilities list
if 'mergeinfo' not in sys.argv[3].split(':'):
  sys.stderr.write("""\
ERROR: Commits to this repository must be made using Subversion
clients which support the merge tracking feature.  Please upgrade
your client to at least Subversion 1.5.0.
""")
  sys.exit(1)

从 Subversion 1.8 开始,针对 Subversion 1.8 服务器提交的客户端仍然会提供功能能力字符串,但还会通过 短暂事务属性 提供有关自身的额外信息。短暂事务属性本质上是修订属性,它们由客户端在提交时尽早地设置在提交事务上,但会在事务最终成为最终修订版之前由服务器自动删除。您可以使用与检查其他未版本化的属性相同的工具来检查这些属性,这些属性在开始提交和预提交存储库挂钩脚本运行之间的时间范围内设置为提交事务。

以下是 Subversion 目前提供和实现的短暂事务属性

svn:txn-client-compat-version

携带提交客户端声称兼容的 Subversion 库版本字符串。这对于确定客户端是否支持正确处理存储库数据所需的最小功能集很有用。

svn:txn-user-agent

携带 用户代理 字符串,该字符串描述提交的客户端程序。Subversion 的库定义了此字符串的初始部分,但 API 的第三方使用者(GUI 客户端等)可以向其中追加自定义信息。

[Note] 注意

虽然大多数客户端会在提交过程的早期传输短暂事务属性,以便 start-commit 挂钩脚本可以检查它们,但 Subversion 的某些配置会导致这些属性在提交过程的后期才设置在事务上。管理员应考虑在 start-commit 和预提交挂钩中执行基于短暂事务属性的任何验证——前者是在这些客户端传输提交有效负载之前排除无效客户端;后者 以防万一 start-commit 挂钩无法执行验证检查。

如前所述,短暂事务属性会在事务提升为新修订版之前从事务中删除。一些管理员可能希望无限期地保留这些属性中的信息。我们建议您使用预提交挂钩脚本将这些属性的值复制到新的属性名称。事实上,Subversion 源代码分发提供了一个 persist-ephemeral-txnprops.py 脚本(位于 tools/hook-scripts/ 子目录中)用于精确地执行此操作。

第三种常见的挂钩脚本使用类型用于复制。无论您是在驱动简单的备份过程还是更复杂的远程存储库镜像场景,挂钩脚本都至关重要。请参阅 名为“存储库备份”的部分名为“存储库复制”的部分,以获取有关存储库维护这些方面的更多信息。

查找挂钩脚本或编写自己的脚本

您可以想象,Subversion 挂钩程序和脚本并不少见,它们可以从 Subversion 社区本身或其他地方免费获得。事实上,Subversion 分发在其 tools/hook-scripts/ 子目录中提供了几个常用的挂钩脚本。但是,如果您无法找到满足您特定需求的脚本,您可以考虑编写自己的脚本。请参阅 第 8 章,嵌入 Subversion,以了解有关使用 Subversion 的公共 API 开发软件的信息。

[Warning] 警告

挂钩脚本几乎可以做任何事情,但挂钩脚本作者应该表现出克制。您可能会想使用挂钩脚本来自动更正提交的文件中存在的错误、缺陷或策略违反行为。不幸的是,这样做会导致问题。Subversion 保持存储库数据的某些位的客户端缓存,如果您以这种方式更改提交事务,这些缓存将变得无法察觉地陈旧,从而导致令人惊讶和意外的行为。虽然通过挂钩脚本添加新的提交事务属性通常是可以的,但提交事务的几乎所有其他内容都应被视为只读。不要修改事务以抛光其有效负载,只需在预提交挂钩中 验证 事务,如果事务不满足所需的要求,则拒绝提交。作为奖励,您的用户将了解认真、合规的工作习惯的价值。

FSFS 配置

从 Subversion 1.6 开始,FSFS 文件系统有一些可配置参数,管理员可以使用这些参数来微调其存储库的性能或磁盘使用情况。您可以在存储库中的 db/fsfs.conf 文件中找到这些选项以及它们的文档。

TortoiseSVN 官方中文版 1.14.7 发布