本文档尚未完善,内容可能会发生重大变化,可能无法准确描述任何已发布的 Apache™ Subversion® 软件版本。将此页面添加为书签或以其他方式推荐给其他人可能不是明智之举。请访问 https://svnbooks.subversion.org.cn/ 获取此书的稳定版本。

稀疏目录

默认情况下,大多数 Subversion 对目录的操作都是以递归方式执行的。例如,svn checkout 会创建一个工作副本,其中包含存储库中指定区域内的所有文件和目录,并递归地向下遍历存储库树,直到将整个结构复制到您的本地磁盘。Subversion 1.5 引入了一种名为 稀疏目录(或 浅层检出)的功能,它允许您轻松地检出一个工作副本(或工作副本的一部分),其深度比完全递归更浅,并可以随时自由地引入之前忽略的文件和子目录。

例如,假设我们有一个存储库,其中包含一个由人类家庭成员及其宠物命名的文件和目录树。(这是一个奇怪的例子,请耐心阅读。)常规的 svn checkout 操作将为我们提供整个树的工作副本

$ svn checkout file:///var/svn/repos mom
A    mom/son
A    mom/son/grandson
A    mom/daughter
A    mom/daughter/granddaughter1
A    mom/daughter/granddaughter1/bunny1.txt
A    mom/daughter/granddaughter1/bunny2.txt
A    mom/daughter/granddaughter2
A    mom/daughter/fishie.txt
A    mom/kitty1.txt
A    mom/doggie1.txt
Checked out revision 1.
$

现在,我们再次检出同一个树,但这次我们将要求 Subversion 只提供最顶层的目录,而不包含其任何子目录

$ svn checkout file:///var/svn/repos mom-empty --depth empty
Checked out revision 1
$

请注意,我们在原始的 svn checkout 命令行中添加了一个新的 --depth 选项。此选项存在于 Subversion 的许多子命令中,类似于 --non-recursive (-N) 和 --recursive (-R) 选项。实际上,它结合、改进、取代并最终淘汰了这两个较旧的选项。首先,它扩展了用户可用的深度规范支持度,添加了一些以前不支持(或支持不一致)的深度。以下是您可以在给定 Subversion 操作中请求的深度值

--depth empty

仅包含操作的直接目标,不包含其任何文件或目录子项。

--depth files

包含操作的直接目标及其所有直接文件子项。

--depth immediates

包含操作的直接目标及其所有直接文件或目录子项。目录子项本身将为空。

--depth infinity

包含直接目标、其文件和目录子项、其子项的子项,依此类推,直到完全递归。

当然,仅仅将两个现有选项合并为一个,并不构成一项值得我们在书中专门用一节来介绍的新功能。幸运的是,故事还有更多内容。这种深度的概念不仅扩展到您使用 Subversion 客户端执行的操作,而且还作为工作副本成员的 环境深度 的描述,它是工作副本为该项持久记录的深度。它的主要优势在于这种持久性——它是一个 粘性 属性。工作副本会记住您为其中每个项选择的深度,直到您稍后更改该深度选择;默认情况下,Subversion 命令会在所有存在的工作副本成员上执行操作,而无论它们选择的深度设置如何。

[Tip] 提示

您可以使用 svn info 命令检查工作副本的记录环境深度。如果环境深度不是完全递归,则 svn info 将显示一行描述该深度值的文本

$ svn info mom-immediates | grep "^Depth:"
Depth: immediates
$

我们之前的示例演示了无限深度(svn checkout 的默认值)和空深度的检出。现在让我们看看其他深度值的示例

$ svn checkout file:///var/svn/repos mom-files --depth files
A    mom-files/kitty1.txt
A    mom-files/doggie1.txt
Checked out revision 1.
$ svn checkout file:///var/svn/repos mom-immediates --depth immediates
A    mom-immediates/son
A    mom-immediates/daughter
A    mom-immediates/kitty1.txt
A    mom-immediates/doggie1.txt
Checked out revision 1.
$

如前所述,这些深度中的每一个都比仅包含目标更进一步,但又比完全递归少一些。

我们在这里使用 svn checkout 作为示例,但您也会发现 --depth 选项存在于 Subversion 的许多其他命令中。在这些其他命令中,深度规范是限制操作范围到某个深度的途径,就像较旧的 --non-recursive (-N) 和 --recursive (-R) 选项的行为方式一样。这意味着,当对某个深度的工作副本进行操作时,同时请求更浅的深度操作,则操作将被限制在该更浅的深度。实际上,我们可以做一个更一般的陈述:给定一个任意(甚至混合)环境深度的工作副本,以及一个具有某些请求操作深度的 Subversion 命令,该命令将保持工作副本成员的环境深度,同时仍将操作范围限制在请求的(或默认的)操作深度。

除了 --depth 选项之外,svn updatesvn switch 子命令还接受第二个与深度相关的选项:--set-depth。正是通过此选项,您可以更改工作副本项的粘性深度。观察当我们使用 svn update --set-depth NEW-DEPTH TARGET 对空深度检出进行逐渐缩放到更深层级时的变化

$ svn update --set-depth files mom-empty
Updating 'mom-empty':
A    mom-empty/kittie1.txt
A    mom-empty/doggie1.txt
Updated to revision 1.
$ svn update --set-depth immediates mom-empty
Updating 'mom-empty':
A    mom-empty/son
A    mom-empty/daughter
Updated to revision 1.
$ svn update --set-depth infinity mom-empty
Updating 'mom-empty':
A    mom-empty/son/grandson
A    mom-empty/daughter/granddaughter1
A    mom-empty/daughter/granddaughter1/bunny1.txt
A    mom-empty/daughter/granddaughter1/bunny2.txt
A    mom-empty/daughter/granddaughter2
A    mom-empty/daughter/fishie1.txt
Updated to revision 1.
$

随着我们逐渐增加深度选择,存储库为我们提供了更多树的部分。

在我们的示例中,我们只对工作副本的根目录进行操作,更改了它的环境深度值。但我们也可以独立地更改工作副本中 任何 子目录的环境深度值。仔细利用此功能,我们可以只构建工作副本树的某些部分,而完全省略其他部分(因此该功能名称中的 稀疏 一词)。以下是一个示例,说明我们如何构建家庭树的一个分支的部分,对另一个分支启用完全递归,并保留其他部分(从磁盘中删除)。

$ rm -rf mom-empty
$ svn checkout file:///var/svn/repos mom-empty --depth empty
Checked out revision 1.
$ svn update --set-depth empty mom-empty/son
Updating 'mom-empty/son':
A    mom-empty/son
Updated to revision 1.
$ svn update --set-depth empty mom-empty/daughter
Updating 'mom-empty/daughter':
A    mom-empty/daughter
Updated to revision 1.
$ svn update --set-depth infinity mom-empty/daughter/granddaughter1
Updating 'mom-empty/daughter/granddaughter1':
A    mom-empty/daughter/granddaughter1
A    mom-empty/daughter/granddaughter1/bunny1.txt
A    mom-empty/daughter/granddaughter1/bunny2.txt
Updated to revision 1.
$

幸运的是,在一个工作副本中拥有复杂的集合的环境深度并不会使您与该工作副本的交互方式变得复杂。您仍然可以在工作副本中创建、回滚、显示和提交本地修改,而无需为相关子命令提供任何新的选项(包括 --depth--set-depth)。即使是 svn update 在没有提供特定深度时也能像其他地方一样工作——它会更新存在的工作副本目标,同时尊重它们的粘性深度。

此时,您可能想知道 所以呢?我什么时候会使用它呢? 此功能在特定存储库布局中会很有用,尤其是在您将许多相关或相互依赖的项目或软件模块作为同级节点保存在单个存储库位置 (trunk/project1, trunk/project2, trunk/project3 等) 时。在这种情况下,您可能只关心其中少数几个项目——也许是某个主要项目以及它依赖的几个其他模块。您可以检出这些项目的单个工作副本,但这些工作副本是分离的,因此,同时对多个或所有工作副本执行操作可能很麻烦。另一种方法是使用稀疏目录功能,构建一个只包含您关心的模块的工作副本。您可以从对项目的公共父目录进行空深度检出开始,然后只对您希望拥有的项进行无限深度更新,就像我们在前面示例中演示的那样。将其视为工作副本成员的“选择加入”系统。

最初(Subversion 1.5)的浅层检出实现很好,但不支持工作副本项的“反缩进”。Subversion 1.6 解决了这个问题。例如,在无限深度工作副本中运行 svn update --set-depth empty 将会丢弃除最顶层目录之外的所有内容。[27] Subversion 1.6 还引入了另一个受支持的 --set-depth 选项值:exclude。在 svn update 中使用 --set-depth exclude 将会导致更新目标从工作副本中完全删除——目录目标甚至不会保留为空。当您希望在工作副本中保留更多东西而不是您希望 保留的东西时,这尤其有用。

假设一个目录包含数百个子目录,其中有一个您希望从工作副本中省略。使用稀疏目录的“添加”方法,您可能会以空深度检出该目录,然后显式地缩进(使用 svn update --set-depth infinity)该目录中除您不关心的目录之外的每个子目录。

$ svn checkout http://svn.example.com/repos/many-dirs --depth empty
…
$ svn update --set-depth infinity many-dirs/wanted-dir-1
…
$ svn update --set-depth infinity many-dirs/wanted-dir-2
…
$ svn update --set-depth infinity many-dirs/wanted-dir-3
…
### and so on, and so on, ...

这可能非常繁琐,尤其是在您的工作副本中甚至没有这些目录的存根来处理时。这样的工作副本还将具有您可能不希望或不期望的另一个特征:如果其他人在此顶级目录中创建了任何新的子目录,则您在更新工作副本时将不会收到这些子目录。

从 Subversion 1.6 开始,您可以采用不同的方法。首先,以完全深度检出该目录。然后在您不关心的一个子目录上运行 svn update --set-depth exclude

$ svn checkout http://svn.example.com/repos/many-dirs
…
$ svn update --set-depth exclude many-dirs/unwanted-dir
D         many-dirs/unwanted-dir
$

这种方法会使您的工作副本保留与第一种方法相同的内容,但顶级目录中出现的任何新子目录也会在您更新工作副本时显示。这种方法的缺点是,您必须实际检出您甚至不想要的那个整个子目录,以便告诉 Subversion 您不想要它。如果该子目录太大而无法放入您的磁盘(这可能是您不希望它在工作副本中的原因),这甚至可能无法实现。

[Note] 注意

虽然从工作副本中排除现有项的功能是挂在 svn update 命令上的,但您可能已经注意到,svn update --set-depth exclude 的输出与正常更新操作的输出不同。此输出暴露了一个事实,即在底层,排除是一个完全的客户端操作,与典型的更新完全不同。

在这种情况下,您可能需要考虑折中的方法。首先,以 --depth immediates 深度检出顶级目录。然后,使用 svn update --set-depth exclude 排除您不想要的目录。最后,将所有保留的项缩进到无限深度,这应该非常容易,因为它们都在您的 shell 中可以访问。

$ svn checkout http://svn.example.com/repos/many-dirs --depth immediates
…
$ svn update --set-depth exclude many-dirs/unwanted-dir
D         many-dirs/unwanted-dir
$ svn update --set-depth infinity many-dirs/*
…
$

再次强调,您的工作副本将与之前两种情况中的内容相同。但是现在,只要将新的文件或子目录提交到顶层目录,您就会在更新工作副本时收到它,而且是空深度。您现在可以决定如何处理这些新出现的 工作副本项:将它们展开到无限深度,或完全排除它们。



[27] 当然,安全起见。与其他情况一样,Subversion 将保留您修改过的或未版本化的任何文件。

TortoiseSVN 官方中文版 1.14.7 发布