手册

Subversion 实战

工作副本

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

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

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

工作副本还包含一些由 Subversion 创建和维护的额外文件,以帮助它执行这些命令。特别是,您的工作副本包含一个名为 .svn 的子目录,也称为工作副本 管理目录 。此管理目录中的文件帮助 Subversion 识别哪些文件包含未发布的更改,以及哪些文件相对于其他人的工作已过时。在 1.7 之前的 Subversion 中,在工作副本的每个版本控制目录中都维护着 .svn 管理子目录。Subversion 1.7 采用了一种完全不同的方法,每个工作副本现在只有一个管理子目录,它是该工作副本根目录的直接子目录。

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

例如,假设您有一个包含两个软件项目的存储库。

图 2.6 存储库的文件系统

The Repository's Filesystem

换句话说,存储库的根目录有两个子目录:paintcalc

要获取工作副本,您必须 检出 存储库的某个子树。(术语 检出 听起来好像与锁定或预留资源有关,但事实并非如此;它只是为您创建项目的私有副本。)

假设您对 button.c 文件进行了修改。由于 .svn 目录记录了文件的修改日期和原始内容,Subversion 可以识别出您对该文件进行了更改。但是,Subversion 不会公开您的更改,直到您明确指示它为止。发布更改的行为通常被称为 提交(或 签入)更改到版本库。

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

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

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

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

请注意,Sally 不需要指定要更新的文件;Subversion 使用 .svn 目录中的信息以及版本库中的其他信息来确定哪些文件需要更新。

版本库 URL

Subversion 版本库可以通过多种不同的方法访问 - 在本地磁盘上,或通过各种网络协议。但是,版本库位置始终是一个 URL。URL 模式指示访问方法。

表 2.1. 版本库访问 URL

模式访问方法
file:// 直接访问本地或网络驱动器上的版本库。
http:// 通过 WebDAV 协议访问支持 Subversion 的 Apache 服务器。
https:// http:// 相同,但使用 SSL 加密。
svn:// 通过自定义协议对 svnserve 服务器进行未经身份验证的 TCP/IP 访问。
svn+ssh:// 通过自定义协议对 svnserve 服务器进行经身份验证的加密 TCP/IP 访问。

在大多数情况下,Subversion 的 URL 使用标准语法,允许将服务器名称和端口号指定为 URL 的一部分。 file:// 访问方法通常用于本地访问,尽管它可以与 UNC 路径一起用于网络主机。因此,URL 的形式为 file://hostname/path/to/repos。对于本地机器,URL 的 hostname 部分必须不存在或为 localhost。出于这个原因,本地路径通常以三个斜杠显示,file:///path/to/repos

此外,在 Windows 平台上使用 file:// 方案的用户需要使用非官方的 标准 语法来访问位于同一台机器上但与客户端当前工作驱动器不同的驱动器上的版本库。以下两种 URL 路径语法中的任何一种都可以在 X 为版本库所在的驱动器的情况下使用

file:///X:/path/to/repos
...
file:///X|/path/to/repos
...
      

请注意,URL 使用普通斜杠,即使 Windows 上路径的本机(非 URL)形式使用反斜杠。

您可以通过网络共享访问 FSFS 存储库,但这推荐,原因有很多。

  • 您正在授予所有用户直接写入权限,因此他们可能会意外删除或损坏存储库文件系统。

  • 并非所有网络文件共享协议都支持 Subversion 所需的锁定。有一天你会发现你的存储库已经被微妙地损坏了。

  • 您必须以正确的方式设置访问权限。SAMBA 在这方面尤其困难。

  • 如果一个人安装了更新版本的客户端,该客户端升级了存储库格式,那么其他人将无法访问存储库,直到他们也升级到新的客户端版本。

修订版

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

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

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

一个很好的方法是将存储库可视化为一系列树。想象一个从 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 会将你的工作副本中的 Makefile 标记为版本 6,以表明它仍然是最新的。因此,在你对工作副本顶层进行干净更新后,它通常会与仓库中的一个版本完全一致。

工作副本如何跟踪仓库

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

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

  • 一个时间戳,记录本地副本上次被仓库更新的时间。

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

未修改,且是最新的

文件在工作目录中没有修改,并且自其工作版本以来,没有对该文件进行任何提交到仓库。对该文件进行 commit 将不会有任何操作,对该文件进行 update 也不会有任何操作。

本地修改,且是最新的

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

未修改,但已过期

文件在工作目录中没有修改,但它在仓库中已被修改。该文件最终应该被更新,以使其与公共版本保持一致。对该文件进行 commit 将不会有任何操作,对该文件进行 update 将把最新的修改合并到你的工作副本中。

本地修改,已过时

该文件在工作目录和仓库中都进行了修改。提交该文件的 提交 将会失败,并出现 过时 错误。应先更新该文件;更新 命令将尝试将公共更改与本地更改合并。如果 Subversion 无法以合理的方式自动完成合并,则会将冲突留给用户解决。

TortoiseSVN 主页