您已经阅读了关于工作副本的内容;现在我们将演示 Subversion 客户端如何创建和使用它们。
Subversion 工作副本是您本地系统上的普通目录树,包含一系列文件。您可以随意编辑这些文件,如果它们是源代码文件,您可以像往常一样从中编译您的程序。您的工作副本是您自己的私有工作区:除非您明确告知 Subversion 这样做,否则它永远不会合并其他人的更改,也不会让其他人看到您自己的更改。
在您对工作副本中的文件进行了一些更改并验证它们工作正常后,Subversion 为您提供命令来发布您对与您一起从事项目的其他人的更改(通过写入到存储库)。如果其他人发布了他们自己的更改,Subversion 为您提供命令将这些更改合并到您的工作目录中(通过从存储库读取)。
工作副本还包含一些额外的文件,这些文件由 Subversion 创建和维护,以帮助它执行这些命令。特别是,您的工作副本包含一个名为 .svn
的子目录,也称为工作副本管理目录。此管理目录中的文件帮助 Subversion 识别哪些文件包含未发布的更改,以及哪些文件相对于其他人的工作而言已过时。在 1.7 之前的 Subversion 版本中,会在工作副本的每个版本控制目录中维护 .svn
管理子目录。Subversion 1.7 采用了完全不同的方法,现在每个工作副本只有一个管理子目录,它是该工作副本根目录的直接子级。
典型的 Subversion 存储库通常保存多个项目的文件(或源代码);通常,每个项目都是存储库文件系统树中的一个子目录。在这种安排中,用户的工作副本通常对应于存储库的特定子树。
例如,假设您有一个包含两个软件项目的存储库。
换句话说,存储库的根目录有两个子目录:paint
和 calc
。
要获取工作副本,您必须检出存储库的某些子树。(术语检出听起来可能与锁定或保留资源有关,但事实并非如此;它只是为您创建一个项目的私有副本。)
假设您对 button.c
进行了更改。由于 .svn
目录记住了文件的修改日期和原始内容,因此 Subversion 可以判断您已更改了该文件。但是,在您明确告知 Subversion 之前,Subversion 不会公开您的更改。发布您的更改的行为更普遍地称为向存储库提交(或签入)更改。
要将您的更改发布给其他人,您可以使用 Subversion 的 commit 命令。
现在,您对 button.c
的更改已提交到存储库;如果另一个用户检出 /calc
的工作副本,他们将在文件的最新版本中看到您的更改。
假设您有一个合作者 Sally,她与您同时检出了 /calc
的工作副本。当您提交对 button.c
的更改时,Sally 的工作副本保持不变;Subversion 仅在用户请求时才修改工作副本。
为了使她的项目保持最新,Sally 可以要求 Subversion 更新她的工作副本,方法是使用 Subversion 的 update 命令。这将把您的更改以及自她检出以来提交的任何其他更改合并到她的工作副本中。
请注意,Sally 不需要指定要更新哪些文件;Subversion 使用 .svn
目录中的信息以及存储库中的更多信息来决定哪些文件需要更新。
可以通过多种不同的方法访问 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 ...
请注意,即使 Windows 上的路径的本机(非 URL)形式使用反斜杠,URL 也使用普通斜杠。
您可以通过网络共享访问 FSFS 存储库,但这不建议这样做,原因如下
您正在向所有用户授予直接写入访问权限,因此他们可能会意外删除或损坏存储库文件系统。
并非所有网络文件共享协议都支持 Subversion 所需的锁定。有一天您会发现您的存储库已被微妙地损坏。
您必须以正确的方式设置访问权限。SAMBA 在这方面尤其困难。
如果一个人安装了较新版本的客户端,该客户端升级了存储库格式,那么其他所有人将无法访问存储库,直到他们也升级到新客户端版本。
svn commit 操作可以将对任意数量的文件和目录的更改作为单个原子事务发布。在您的工作副本中,您可以更改文件内容、创建、删除、重命名和复制文件和目录,然后将完整的更改集作为一个单元提交。
在存储库中,每次提交都被视为原子事务:要么所有提交的更改都发生,要么都不发生。Subversion 在面对程序崩溃、系统崩溃、网络问题和其他用户的操作时,都保持了这种原子性。
每次存储库接受提交时,都会创建一个新的文件系统树状态,称为修订版本。每个修订版本都分配有一个唯一的自然数,该数比上一个修订版本的编号大一。新创建的存储库的初始修订版本编号为零,并且只包含一个空根目录。
将存储库可视化为一系列树是一个不错的方法。想象一个修订版本号数组,从 0 开始,从左向右延伸。每个修订版本号下方都悬挂着一个文件系统树,每个树都是存储库在每次提交后外观的“快照”。
重要的是要注意,工作副本并不总是对应于存储库中的任何单个修订版本;它们可能包含来自多个不同修订版本的文件。例如,假设您从最新修订版本为 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 操作会将最新更改折叠到您的工作副本中。
文件在工作目录和存储库中都已更改。对文件执行 commit 操作将失败,并显示过时错误。应首先更新该文件;update 命令将尝试将公共更改与本地更改合并。如果 Subversion 无法以合理的方式自动完成合并,则将其留给用户来解决冲突。