本手册旨在描述 Subversion 1.1。如果您运行的是更新版本的 Subversion,我们强烈建议您访问 https://svnbooks.subversion.org.cn/ 并查阅适合您 Subversion 版本的版本。

Subversion 实战

现在是时候从抽象走向具体了。在本节中,我们将展示 Subversion 被使用的真实示例。

工作副本

您已经阅读了有关工作副本的信息;现在我们将演示 Subversion 客户端如何创建和使用它们。

Subversion 工作副本是您本地系统上的一个普通目录树,包含一组文件。您可以随意编辑这些文件,如果它们是源代码文件,您可以像往常一样从它们中编译程序。您的工作副本是您自己的私人工作区:Subversion 永远不会合并其他人的更改,也不会让您自己的更改对其他人可用,直到您明确告诉它这样做。

在您对工作副本中的文件进行了一些更改并验证它们正常工作之后,Subversion 提供了命令来“发布”您的更改到与您一起处理项目的其他人(通过写入存储库)。如果其他人发布了自己的更改,Subversion 会为您提供将这些更改合并到您的工作目录中的命令(通过从存储库中读取)。

工作副本还包含一些额外的文件,由 Subversion 创建和维护,以帮助它执行这些命令。特别是,工作副本中的每个目录都包含一个名为.svn的子目录,也称为工作副本 管理目录。每个管理目录中的文件帮助 Subversion 识别哪些文件包含未发布的更改,以及哪些文件相对于其他人的工作而言已过时。

典型的 Subversion 存储库通常保存多个项目的​​文件(或源代码);通常,每个项目都是存储库文件系统树中的一个子目录。在这种安排下,用户的 ​​工作副本通常对应于存储库的特定子树。

例如,假设您有一个存储库,其中包含两个软件项目,paintcalc。每个项目都位于自己的顶级子目录中,如 图 2.6,“存储库的文件系统” 所示。

图 2.6. 存储库的文件系统

The repository's filesystem

要获取工作副本,您必须 检出存储库的某个子树。(术语“检出”听起来似乎与锁定或保留资源有关,但事实并非如此;它只是为您创建项目的私人副本。)例如,如果您检出/calc,您将获得一个这样的工作副本

$ svn checkout http://svn.example.com/repos/calc
A  calc
A  calc/Makefile
A  calc/integer.c
A  calc/button.c

$ ls -A calc
Makefile  integer.c  button.c  .svn/

字母 A 的列表表明 Subversion 正在将许多项目添加到您的工作副本中。您现在拥有存储库的个人副本/calc目录,其中包含一个额外的条目——.svn——其中包含 Subversion 需要​​的额外信息,如前所述。

假设您对button.c进行了更改。由于.svn目录记得文件的修改日期和原始内容,Subversion 可以判断您是否已更改了文件。但是,Subversion 不会公开您的更改,直到您明确告诉它这样做。发布更改的行为通常被称为 提交(或 签入)更改到存储库。

要将您的更改发布给其他人,您可以使用 Subversion 的 commit 命令

$ svn commit button.c
Sending        button.c
Transmitting file data .
Committed revision 57.

现在您对button.c的更改已提交到存储库;如果另一个用户检出一个工作副本/calc,他们将在文件的最新版本中看到您的更改。

假设您有一位合作者 Sally,她在您检出/calc工作副本的同时也检出了一個工作副本。当您提交对button.c的更改时,Sally 的工作副本保持不变;Subversion 仅在用户请求时修改工作副本。

为了使她的项目更新,Sally 可以要求 Subversion 更新她的工作副本,方法是使用 Subversion 的 update 命令。这会将您的更改以及自她检出以来提交的任何其他更改合并到她的工作副本中。

$ pwd
/home/sally/calc

$ ls -A 
.svn/ Makefile integer.c button.c

$ svn update
U button.c

svn update 命令的输出表明 Subversion 更新了button.c的内容。请注意,Sally 不需要指定要更新哪些文件;Subversion 使用.svn目录中的信息以及存储库中的其他信息来决定需要更新哪些文件。

修订版

一个 svn commit 操作可以将对任意数量的文件和目录的更改发布为单个原子事务。在您的工作副本中,您可以更改文件的​​内容、创建、删除、重命名和复制文件和目录,然后将完整的更改集作为单元提交。

在存储库中,每个提交都被视为一个原子事务:要么所有提交的更改都发生,要么都不发生。Subversion 尝试在程序崩溃、系统崩溃、网络问题和其他用户的操作面前保留这种原子性。

每次存储库接受提交时,都会创建一个新的文件系统树状态,称为 修订版。每个修订版都分配一个唯一的自然数,比前一个修订版的数字大 1。新创建的存储库的初始修订版编号为零,只包含一个空的根目录。

图 2.7,“存储库” 说明了可视化存储库的一种好方法。想象一个从左到右延伸的修订版编号数组,从 0 开始。每个修订版编号下面都挂着一个文件系统树,每个树都是提交后存储库外观的“快照”。

图 2.7. 存储库

The repository

重要的是要注意,工作副本并不总是对应于存储库中的任何单个修订版;它们可能包含来自多个不同修订版的文件。例如,假设您从存储库中检出一个工作副本,该存储库的最新修订版是 4

calc/Makefile:4
     integer.c:4
     button.c:4

目前,此工作目录完全对应于存储库中的修订版 4。但是,假设您对button.c进行了更改,并提交了该更改。假设没有其他提交发生,您的提交将创建存储库的修订版 5,而您的工作副本现在将如下所示

calc/Makefile:4
     integer.c:4
     button.c:5

假设此时,Sally 提交了对integer.c的更改,创建了修订版 6。如果您使用 svn update 将您的工作副本更新到最新状态,那么它将如下所示

calc/Makefile:6
     integer.c:6
     button.c:6

Sally 对integer.c的更改将出现在您的工作副本中,而您的更改将仍然存在于button.c中。在此示例中,Makefile的文本在修订版 4、5 和 6 中是相同的,但 Subversion 会用修订版 6 标记您的工作副本Makefile,以表明它仍然是最新的。因此,在您对工作副本的顶层执行干净的更新后,它通常会完全对应于存储库中的一个修订版。

工作副本如何跟踪存储库

对于工作目录中的每个文件,Subversion 会在.svn/管理区域中记录两条基本信息

  • 您的工作文件基于哪个修订版(这被称为文件的 工作修订版),以及

  • 记录本地副本上次由存储库更新的时间的时间戳。

有了这些信息,Subversion 可以通过与存储库对话来判断工作文件处于以下四种状态中的哪一种

未更改且最新

该文件在工作目录中未更改,并且自其工作修订版以来,尚未对该文件进行任何更改提交到存储库。对该文件的 svn commit 不会执行任何操作,对该文件的 svn update 也不会执行任何操作。

本地已更改且最新

该文件已在工作目录中更改,并且自其基本修订版以来,尚未对该文件进行任何更改提交到存储库。存在尚未提交到存储库的本地更改,因此对该文件的 svn commit 将成功发布您的更改,对该文件的 svn update 不会执行任何操作。

未更改且已过时

该文件在工作目录中未更改,但已在存储库中更改。该文件应该最终更新,以使其与公共修订版保持一致。对该文件的 svn commit 不会执行任何操作,对该文件的 svn update 将将最新更改折叠到您的工作副本中。

本地已更改且已过时

文件在工作目录和仓库中都已更改。对文件执行 svn commit 命令将导致“过期”错误。应先更新文件;svn update 命令将尝试将公共更改与本地更改合并。如果 Subversion 无法自动以合理的方式完成合并,它将留给用户解决冲突。

这听起来可能需要跟踪很多内容,但 svn status 命令将显示工作副本中任何项目的狀態。有关该命令的更多信息,请参阅 名为“svn status”的部分

混合修订版的局限性

一般来说,Subversion 试图尽可能灵活。一种特殊的灵活性是可以拥有包含混合修订号的工作副本。

一开始,可能并不完全清楚为什么这种灵活性被认为是一种功能,而不是一种负债。完成对仓库的提交后,新提交的文件和目录的版本比工作副本的其余部分更更新。这看起来有点乱。如前所述,通过运行 svn update,工作副本始终可以被带到单个工作版本。为什么有人会 故意想要混合工作版本呢?

假设您的项目足够复杂,您会发现有时将工作副本的部分强制“回溯”到较早的版本是件好事;您将在第 3 章中学习如何做到这一点。也许您想测试子目录中包含的子模块的早期版本,或者您可能想在最新树的上下文中检查文件的多个先前版本。

无论您如何在工作副本中使用混合版本,这种灵活性都有一些限制。

首先,您不能提交尚未完全更新的文件或目录的删除操作。如果仓库中存在该项目的更新版本,则您的删除尝试将被拒绝,以防止您意外删除您尚未看到的更改。

其次,您不能对尚未完全更新的目录提交元数据更改。您将在第 6 章中了解到如何将“属性”附加到项目。目录的工作版本定义了一组特定的条目和属性,因此对过期目录提交属性更改可能会破坏您尚未看到的属性。

TortoiseSVN 官方中文版 1.14.7 发布