本文档旨在描述 Subversion 1.1。如果您正在运行较新版本的 Subversion,我们强烈建议您访问 https://svnbook.subversion.org.cn/ 并查阅适合您 Subversion 版本的书籍版本。

外部定义

有时,构建由多个不同检出组成的工作副本很有用。例如,您可能希望不同的子目录来自存储库中的不同位置,或者可能来自完全不同的存储库。您当然可以通过手动操作来设置这种情况 - 使用 svn checkout 来创建您试图实现的嵌套工作副本结构。但如果此布局对使用您的存储库的所有人来说都很重要,那么其他每个用户都需要执行与您相同的检出操作。

幸运的是,Subversion 支持 外部定义。外部定义是本地目录到版本化资源的 URL(以及可能特定的修订版本)的映射。在 Subversion 中,您使用svn:externals属性以组的形式声明外部定义。您可以使用 svn propsetsvn propedit 创建或修改此属性(请参阅 名为“为什么使用属性?”的部分)。它可以设置在任何版本化的目录上,其值是子目录(相对于设置属性的版本化目录)和完全限定的、绝对的 Subversion 存储库 URL 的多行表格。

$ svn propget svn:externals calc
third-party/sounds             http://sounds.red-bean.com/repos
third-party/skins              http://skins.red-bean.com/repositories/skinproj
third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker

svn:externals属性的便利之处在于,一旦它被设置为一个版本化的目录,每个检出包含该目录的工作副本的人都会受益于外部定义。换句话说,一旦一个人花时间定义了那些嵌套的工作副本检出,其他人就不用再费心了 - Subversion 将在检出原始工作副本时,也检出外部工作副本。

请注意之前的外部定义示例。当有人检出一个calc目录的工作副本时,Subversion 会继续检出其外部定义中找到的项目。

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

Fetching external item into calc/third-party/sounds
A  calc/third-party/sounds/ding.ogg
A  calc/third-party/sounds/dong.ogg
A  calc/third-party/sounds/clang.ogg
…
A  calc/third-party/sounds/bang.ogg
A  calc/third-party/sounds/twang.ogg
Checked out revision 14.

Fetching external item into calc/third-party/skins
…

如果您需要更改外部定义,可以使用常规的属性修改子命令来进行。当您提交对svn:externals属性的更改时,Subversion 将在您下次运行 svn update 时,根据更改后的外部定义同步检出的项目。当其他人更新其工作副本并接收您对外部定义的更改时,也会发生同样的事情。

svn status 命令也识别外部定义,显示状态代码为X对于检出外部的独立子目录,然后递归进入这些子目录以显示外部项目本身的状态。

Subversion 中对外部定义的支持可能有点误导人。首先,外部定义只能指向目录,而不是文件。其次,外部定义不能指向相对路径(例如../../skins/myskin)。第三,通过外部定义支持创建的工作副本仍然与主工作副本分离(实际上设置了svn:externals属性的版本化目录)。并且 Subversion 仍然只真正操作非独立的工作副本。因此,例如,如果您想提交对一个或多个外部工作副本所做的更改,您必须在这些工作副本上显式运行 svn commit - 在主工作副本上提交不会递归进入任何外部工作副本。

此外,由于定义本身使用绝对 URL,因此移动或复制附加了它们的目录不会影响检出为外部的内容(尽管相对本地目标子目录当然会随着重命名目录一起移动)。这在某些情况下可能会让人困惑 - 甚至让人沮丧。例如,如果您在/trunk开发线中的目录上使用外部定义,这些定义指向该行的其他区域,然后您使用 svn copy 将该线分支到某个新位置/branches/my-branch,新分支中项目上的外部定义仍然会引用/trunk中的版本化资源。此外,请注意,如果您需要重新父级您的工作副本(使用 svn switch --relocate),外部定义不会也被重新父级。