本手册旨在描述 Subversion 1.6.x 系列。如果您运行的是其他版本的 Subversion,我们强烈建议您访问 https://svnbook.subversion.org.cn/ 并参考与您的 Subversion 版本相匹配的手册版本。
由于 Subversion 版本库的整体设计以及它所依赖的技术非常简单,因此创建和配置版本库是相当简单的任务。您需要做出一些初步的决定,但涉及到任何给定 Subversion 版本库设置的实际工作都非常基础,如果您发现自己正在设置多个此类东西,那么它会倾向于无意识的重复。
不过,您事先需要考虑一些事项,例如
您期望在您的版本库(或版本库)中存储哪些数据,以及这些数据将如何组织?
您的版本库将在哪里存储,以及如何访问它?
您需要什么类型的访问控制和版本库事件报告?
您要使用哪种可用的数据存储类型?
在本节中,我们将尝试帮助您回答这些问题。
虽然 Subversion 允许您在不丢失任何信息的情况下移动版本化的文件和目录,甚至提供将整个版本化的历史记录集从一个版本库移动到另一个版本库的方法,但这样做可能会极大地破坏那些经常访问版本库并期望事物位于特定位置的人的工作流程。因此,在创建新版本库之前,请尝试展望未来;在将数据置于版本控制之下之前,请提前做好计划。通过认真地 “布局” 您的版本库或版本库及其版本化的内容,您可以避免许多未来的麻烦。
假设作为版本库管理员,您将负责支持多个项目的版本控制系统。您的第一个决定是使用单个版本库来管理多个项目,还是为每个项目提供一个单独的版本库,或者是对这两种方法的某种折衷方案。
使用单个版本库来管理多个项目有其优势,最明显的是缺乏重复维护。单个版本库意味着只有一套挂钩程序,一个需要定期备份的东西,一个需要在 Subversion 发布不兼容的新版本时转储和加载的东西,等等。此外,您可以在项目之间轻松地移动数据,而不会丢失任何历史版本信息。
使用单个版本库的缺点是,不同的项目可能对版本库事件触发器有不同的要求,例如需要向不同的邮件列表发送提交通知电子邮件,或者对构成合法提交的内容有不同的定义。当然,这些并不是不可克服的问题,这仅仅意味着您所有的挂钩脚本都必须对版本库的布局敏感,而不是假设整个版本库与单一组人员相关联。此外,请记住 Subversion 使用版本库范围内的修订号。虽然这些数字没有任何特殊的魔力,但有些人仍然不喜欢这样一个事实,即使他们的项目最近没有进行任何更改,版本库的最新修订号一直在上升,因为其他项目正在积极添加新的修订版。[31]
也可以采用折衷方案。例如,可以根据项目之间的关联程度进行分组。您可能有一些版本库,每个版本库中包含几个项目。这样,那些可能想要共享数据的项目可以轻松地做到这一点,并且随着新修订版添加到版本库中,至少开发人员知道这些新修订版至少与使用该版本库的所有人远程相关。
在决定如何组织您的项目以相对于版本库进行组织之后,您可能希望考虑版本库本身内的目录层次结构。因为 Subversion 使用常规的目录复制来进行分支和标记(参见 第 4 章 分支和合并),Subversion 社区建议您为每个项目根目录选择一个版本库位置,即包含与该项目相关数据的 “最顶层” 目录,然后在该根目录下创建三个子目录:trunk
,表示在其中进行主要项目开发的目录;branches
,它是一个目录,您可以在其中创建主开发线的各种命名分支;以及 tags
,它是一组创建的树快照,可能被销毁,但从不更改。[32]
例如,您的版本库可能看起来像这样
/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ spreadsheet/ trunk/ tags/ branches/ …
请注意,每个项目根目录在您的版本库中的位置无关紧要。如果您每个版本库只有一个项目,那么将每个项目根目录放在该项目的相应版本库的根目录中是合乎逻辑的。如果您有多个项目,您可能希望将它们按组安排在版本库中,也许将具有相似目标或共享代码的项目放在同一个子目录中,或者也许只是按字母顺序对它们进行分组。这样的安排可能看起来像这样
/ utils/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ … office/ spreadsheet/ trunk/ tags/ branches/ …
以您认为合适的方式布局您的版本库。Subversion 不期望或强制执行特定的布局,在其眼中,目录就是目录。最终,您应该选择满足在其中存储项目的开发人员需求的版本库安排。
不过,为了完全公开,我们会提及另一种非常常见的布局。在这种布局中,trunk
、tags
和 branches
目录位于版本库的根目录中,而您的项目位于这些目录下的子目录中,如下所示
/ trunk/ calc/ calendar/ spreadsheet/ … tags/ calc/ calendar/ spreadsheet/ … branches/ calc/ calendar/ spreadsheet/ …
这种布局没有任何特别错误的地方,但它可能对您的用户来说并不直观。尤其是在具有许多用户的庞大、多项目环境中,这些用户可能只熟悉版本库中的一两个项目。但项目作为分支同级的方法往往会淡化项目的个体性,并将重点放在将所有项目作为一个整体。不过,这是一个社会问题。我们喜欢我们最初建议的安排,纯粹出于实际原因,当有一个单独的版本库路径包含该项目以及该项目单独的所有历史记录(过去、现在、已标记和已分支)时,更容易询问(或修改或迁移到其他地方)单个项目的整个历史记录。
在创建 Subversion 版本库之前,您需要回答的一个明显问题是它将存储在何处。这与涉及如何访问版本库(通过 Subversion 服务器或直接访问)、由谁访问(公司防火墙后面的用户或整个互联网上的用户)、您将在 Subversion 周围提供哪些其他服务(版本库浏览界面、基于电子邮件的提交通知等)、您的数据备份策略等等的无数其他问题紧密相关。
我们在 第 6 章 服务器配置 中介绍了服务器选择和配置,但我们在这里想简单说明的是,对其中一些其他问题的答案可能具有影响,从而迫使您在决定版本库将存储在何处时做出选择。例如,某些部署方案可能需要从多台计算机通过远程文件系统访问版本库,在这种情况下(如您将在下一节中读到),您对版本库后端数据存储的选择实际上没有选择,因为只有可用的后端之一可以在这种情况下使用。
解决每个可能的 Subversion 部署方式既不可能,也不在本手册的范围内。我们只是鼓励您使用这些页面和其他来源作为参考材料来评估您的选项,并提前做好计划。
Subversion 为每个版本库使用的底层数据存储类型提供两种选择,通常被称为 “后端” 或,有点令人困惑地,“(版本化的)文件系统”。一种数据存储类型将所有内容都保留在 Berkeley DB(或 BDB)数据库环境中,使用这种类型的版本库通常被称为 “BDB 支持”。另一种类型将数据存储在普通平面文件中,使用自定义格式。Subversion 开发人员习惯于将这种后一种数据存储机制称为 FSFS[33],它是一个版本化的文件系统实现,直接使用本机 OS 文件系统来存储数据,而不是通过数据库库或其他抽象层。
表 5.1,版本库数据存储比较 概述了 Berkeley DB 和 FSFS 版本库的比较。
表 5.1 版本库数据存储比较
类别 | 特征 | Berkeley DB | FSFS |
---|---|---|---|
可靠性 | 数据完整性 | 如果正确部署,非常可靠;Berkeley DB 4.4 带来了自动恢复功能 | 较旧的版本有一些很少发生的但会导致数据破坏的错误 |
对中断的敏感性 | 非常敏感;崩溃和权限问题可能会导致数据库 “卡住”,需要执行日志恢复过程 | 不太敏感 | |
可访问性 | 可从只读挂载中使用 | 不可使用 | 可以使用 |
平台无关的存储 | 不可使用 | 可以使用 | |
可在网络文件系统上使用 | 通常不可使用 | 可以使用 | |
组权限处理 | 对用户 umask 问题敏感;最好由一个用户访问 | 可以解决 umask 问题 | |
可扩展性 | 版本库磁盘使用量 | 较大(尤其是在日志文件未被清除的情况下) | 较小 |
修订版树的数量 | 数据库;没有问题 | 一些较旧的本机文件系统无法很好地扩展到单个目录中包含数千个条目 | |
包含许多文件的目录 | 较慢 | 较快 | |
性能 | 签出最新修订版 | 没有明显的区别 | 没有明显的区别 |
大型提交 | 总体上较慢,但成本在提交的整个生命周期内分摊 | 总体上较快,但最终确定延迟可能会导致客户端超时 |
这两种后端类型各有优缺点。它们之间没有哪个更 “官方”,尽管较新的 FSFS 是从 Subversion 1.2 开始的默认数据存储。两者都足够可靠,可以用来存储您的版本化数据。但如您在 表 5.1,版本库数据存储比较 中看到的那样,FSFS 后端在支持的部署方案方面提供了更多的灵活性。更大的灵活性意味着您需要更努力地找到错误部署它的方法。这些原因以及不使用 Berkeley DB 就意味着系统中少了一个组件,这些原因在很大程度上解释了为什么今天几乎所有人在创建新版本库时都使用 FSFS 后端。
幸运的是,大多数访问 Subversion 仓库的程序并不知道正在使用哪种后端数据存储。而且你甚至不必坚持使用你的第一个数据存储选择——如果你后来改变主意,Subversion 提供了将你的仓库数据迁移到使用不同后端数据存储的另一个仓库的方法。我们将在本章后面更详细地讨论这一点。
以下小节将更详细地介绍可用的后端数据存储类型。
在 Subversion 的初始设计阶段,开发人员决定使用 Berkeley DB,原因很多,包括它的开源许可证、事务支持、可靠性、性能、API 简洁性、线程安全、对游标的支持等等。
Berkeley DB 提供真正的交易支持——可能是它最强大的功能。多个访问你的 Subversion 仓库的进程不必担心意外地覆盖彼此的数据。事务系统提供的隔离使得对于任何给定的操作,Subversion 仓库代码都看到了数据库的静态视图——而不是一个不断被其他进程改变的数据库——并且可以根据该视图做出决策。如果做出的决策恰好与另一个进程正在做的事情发生冲突,整个操作将回滚,就好像它从未发生过一样,Subversion 会优雅地针对新的、更新的(但仍然是静态的)数据库视图重试操作。
Berkeley DB 的另一个很棒的功能是热备份——能够在不将数据库“脱机”的情况下备份数据库环境。我们将在本章后面(在名为“仓库备份”的部分)讨论如何备份你的仓库,但是能够在没有任何停机时间的情况下创建你的仓库的完全功能副本的好处应该是显而易见的。
Berkeley DB 也是一个非常可靠的数据库系统,前提是它被正确使用。Subversion 使用 Berkeley DB 的日志记录功能,这意味着数据库首先将它即将进行的任何修改的描述写入磁盘日志文件,然后才进行修改。这样做是为了确保如果出现任何问题,数据库系统可以备份到以前的检查点——日志文件中已知不损坏的位置——并重播事务,直到数据恢复到可使用状态。有关 Berkeley DB 日志文件的更多信息,请参阅本章后面的名为“管理磁盘空间”的部分。
但是,每一朵玫瑰都有它的刺,所以我们必须注意到 Berkeley DB 的一些已知限制。首先,Berkeley DB 环境不可移植。你不能简单地将一个在 Unix 系统上创建的 Subversion 仓库复制到 Windows 系统上,并期望它能正常工作。虽然 Berkeley DB 数据库格式的大部分内容是与架构无关的,但环境的其他方面则不然。其次,Subversion 以一种无法在 Windows 95/98 系统上运行的方式使用 Berkeley DB——如果你需要在 Windows 机器上托管一个由 BDB 支持的仓库,请坚持使用 Windows 2000 或更高版本。
虽然 Berkeley DB 承诺在满足特定规范的网络共享上正常工作,[34] 但是大多数网络文件系统类型和设备实际上没有满足这些要求。在任何情况下,你都不能允许位于网络共享上的由 BDB 支持的仓库被该共享的多个客户端同时访问(这通常是让仓库位于网络共享上的主要目的)。
![]() |
警告 |
---|---|
如果你试图在不兼容的远程文件系统上使用 Berkeley DB,结果是不可预测的——你可能会立即看到神秘的错误,或者它可能在几个月后你才发现你的仓库数据库已经微妙地损坏。对于需要位于网络共享上的仓库,你应该认真考虑使用 FSFS 数据存储。 |
最后,由于 Berkeley DB 是一个直接链接到 Subversion 的库,因此它比典型的关系数据库系统对中断更敏感。例如,大多数 SQL 系统都有一个专门的服务器进程来仲裁对表的访问。如果一个访问数据库的程序由于某种原因崩溃,数据库守护进程会注意到连接丢失,并清理掉任何残留的混乱。而且由于数据库守护进程是唯一访问表的进程,应用程序不必担心权限冲突。然而,Berkeley DB 情况并非如此。Subversion(以及使用 Subversion 库的程序)直接访问数据库表,这意味着程序崩溃可能会使数据库处于暂时不一致、不可访问的状态。当这种情况发生时,管理员需要要求 Berkeley DB 恢复到检查点,这有点烦人。除了崩溃的进程之外,其他事情也会导致仓库“卡住”,例如程序在数据库文件的所有权和权限上发生冲突。
![]() |
注意 |
---|---|
Berkeley DB 4.4 为 Subversion 带来了(对 Subversion 1.4 及更高版本)让 Subversion 自动透明地恢复需要恢复的 Berkeley DB 环境的能力。当 Subversion 进程连接到仓库的 Berkeley DB 环境时,它会使用一些进程统计机制来检测以前进程的任何不干净断开连接,执行任何必要的恢复,然后继续进行,就好像什么都没有发生一样。这并不能完全消除仓库卡住的情况,但它确实大大减少了从这些情况中恢复所需的人工交互量。 |
因此,虽然 Berkeley DB 仓库速度很快,而且可扩展性很高,但最好由单个服务器进程以一个用户身份运行——例如 Apache 的httpd 或svnserve(参见第 6 章,服务器配置)——而不是通过file://
或svn+ssh://
URL 以多个不同用户身份访问它。如果你以多个用户身份直接访问 Berkeley DB 仓库,请务必阅读本章后面的名为“支持多种仓库访问方法”的部分。
2004 年年中,第二种类型的仓库存储系统——一种根本不使用数据库的系统——出现了。FSFS 仓库将与修订相关的更改存储在一个文件中,因此所有仓库的修订都可以在一个包含编号文件的子目录中找到。事务作为单个文件在单独的子目录中创建。完成后,事务文件被重命名并移动到修订目录,从而保证提交是原子的。而且由于修订文件是永久的、不可改变的,因此仓库也可以在“热”状态下备份,就像由 BDB 支持的仓库一样。
FSFS 修订文件描述了修订的目录结构、文件内容以及与其他修订树中文件的增量。与 Berkeley DB 数据库不同,这种存储格式可以在不同的操作系统之间移植,并且对 CPU 架构不敏感。由于没有使用日志记录或共享内存文件,因此可以安全地在网络文件系统上访问仓库,并在只读环境中进行检查。数据库开销的缺乏也意味着仓库的整体大小会更小一些。
FSFS 也具有不同的性能特性。当提交包含大量文件的目录时,FSFS 能够更快地追加目录条目。另一方面,FSFS 在完成提交时会有更长的延迟,因为它执行了 BDB 后端在提交生命周期内摊销的任务,这在极端情况下会导致客户端在等待响应时超时。
然而,最重要的区别是 FSFS 在出现问题时不会卡住。如果使用 Berkeley DB 数据库的进程遇到了权限问题或突然崩溃,数据库可能会处于不可使用状态,直到管理员恢复它。如果相同的场景发生在使用 FSFS 仓库的进程中,仓库根本不会受到影响。最糟糕的情况是,一些事务数据会被留下。