本手册描述的是 Subversion 1.2。如果您正在运行更新版本的 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 属性的更改时,当您下次运行 svn update 时,Subversion 会根据已更改的外部定义同步检出的项目。当其他人更新他们的工作副本并接收您对外部定义的更改时,也会发生同样的事情。

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

提示

您应该认真考虑在所有外部定义中使用显式修订版本号。这样做意味着您可以在何时提取不同的外部信息快照,以及提取哪个快照方面做出决定。除了不因可能无法控制的第三方存储库的更改而感到意外的常识方面之外,使用显式修订版本号还意味着当您将工作副本回溯到以前的修订版本时,您的外部定义也会恢复到以前的修订版本中的样子,这反过来又意味着外部工作副本将更新以匹配他们 当时 在您的存储库处于该先前修订版本时的样子。对于软件项目而言,这可能是成功构建和失败构建复杂代码库的旧快照之间的区别。

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

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

最后,您可能希望 svn 子命令不识别或以其他方式操作作为外部定义处理结果创建的外部工作副本。在这些情况下,您可以将 --ignore-externals 选项传递给子命令。

TortoiseSVN 官方中文版 1.14.7 发布