存储库指示配置 - 第 1 部分(共 3 部分):可继承属性

本文已获得原始位置 http://blogs.collab.net/subversion/the-road-to-repository-dictated-configuration-day-2-autoprops 的许可,并在此处镜像。已删除或更新了失效链接。

作者:Paul Burba

发布 2013-06-25

这是描述可以在存储库中设置的不同配置选项的三部分系列文章中的第一篇。

属性继承

即使是最普通的 Subversion 用户也可能熟悉版本化的属性。这些名称:值对的元数据被分配给文件或目录。一些(那些名称以“svn:”开头的属性)被 Subversion 本身赋予特殊含义,并在 Subversion 本身中触发特定行为;其余的则由用户或第三方 Subversion 相关工具开放定义和解释。

在 Subversion 1.7 及更早版本中,版本化属性通常只应用于设置它们的特定文件或目录。最多,在目录上设置的属性可能应用于该目录的直接子目录 1。例如,svn:ignore 属性如果存在于目录中,则定义一个未版本化文件模式列表(在同一目录中),这些模式会被 svn status 和其他子命令忽略。

从现在开始,我们将简单地谈论“属性”,而不是区分版本化属性和修订属性——所以请记住,在本系列博客中,我们谈论的是版本化属性!修订属性没有继承的概念。

新发布的 Subversion 1.8 引入了继承属性的概念。这个新功能非常透明,实际上你可以像以前一样使用属性,你可能不会注意到任何区别。这是因为实际上没有“可继承”属性或“不可继承”属性——所有属性都可能被继承!

1.8 中真正不同的是,给定一个工作副本路径(或 URL),Subversion 现在有一个机制来查找该路径的父级上设置的属性。即使路径是工作副本路径,并且路径的父级未在工作副本中找到,这也适用。这种机制通过 svn proplistsvn propget 子命令的新 --show-inherited-props 选项体现出来。

一个简单的例子将展示这个新选项是如何工作的。

注意:在今天的示例中,我将使用无意义的自定义属性。在第二部分和第三部分中,我们将演示一些新的 Subversion 保留属性,这些属性实际上可以完成实际工作;现在我只想演示一些新的核心概念。

假设我们的存储库在存储库的根目录和各种子树上设置了属性 foo。我们可以使用存储库根目录上的递归 svn propget 查看所有这些属性、它们的位置和值 2

1.8.0>svn pg foo http://svn.example.com/repos --verbose --recursive
Properties on 'http://svn.example.com/repos':
  foo
    bar
Properties on 'http://svn.example.com/repos/calc':
  foo
    baz
Properties on 'http://svn.example.com/repos/calc/trunk':
  foo
    qux
Properties on 'http://svn.example.com/repos/paint':
  foo
    fum
Properties on 'http://svn.example.com/repos/paint/trunk':
  foo
    zot

现在让我们检出一个存储库的子树,^/calc/trunk

1.8.0>svn co http://svn.example.com/repos/calc/trunk calc-trunk-wc
A    calc-trunk-wc\doc
A    calc-trunk-wc\src
A    calc-trunk-wc\doc\INSTALL
A    calc-trunk-wc\FAQ
A    calc-trunk-wc\src\real.c
A    calc-trunk-wc\src\main.c
A    calc-trunk-wc\src\button.c
A    calc-trunk-wc\src\integer.c
A    calc-trunk-wc\Makefile
A    calc-trunk-wc\README
 U   calc-trunk-wc
Checked out revision 478.

不出所料,在新建的检出工作副本的根目录上进行递归 propget 只会显示与 ^/calc/trunk 相对应的工作副本路径上的 foo 属性

1.8.0>svn pg foo calc-trunk-wc --verbose --recursive
Properties on 'calc-trunk-wc':
  foo
    qux

相同的 propget 命令,但这次使用新的 --show-inherited-props 选项,会显示工作副本根路径上的相同属性,但也会显示该路径的存储库父级上的 foo 属性

1.8.0>svn pg foo calc-trunk-wc --verbose --recursive --show-inherited-props
Inherited properties on 'calc-trunk-wc',
from 'http://svn.example.com/repos':
  foo
    bar
Inherited properties on 'calc-trunk-wc',
from 'http://svn.example.com/repos/calc':
  foo
    baz
Properties on 'calc-trunk-wc':
  foo
    qux

设置在 ^/paint^/paint/trunk 上的 foo 属性不会显示,因为这些路径不是工作副本的父级。svn proplist 子命令也支持 --show-inherited-props 选项,并且以类似的方式工作,当然,除了所有继承的属性,无论名称如何,都会显示出来。

构建块

所以现在我们有了递归 propget/proplist 的反面;一种向上查看存储库树而不是向下查看存储库树的方法。我们能用这种新发现的能力做什么呢?

请记住,所有在 1.8 之前存在的 Subversion 保留属性只适用于它们设置的路径,或者最多适用于该路径的直接子级 3。您添加到自己存储库中的任何自定义属性可能也是如此——旧属性不会突然获得新的范围。

除了这个警告,属性继承在两种情况下非常有用

第一个是使用新的 Subversion 保留属性 4,这些属性利用继承将属性应用于设置属性的路径下的所有子树。在本博文的第 2 部分中,我们将看到这两个属性中的第一个,svn:auto-props

第二种情况是使用您自己的自定义工具、脚本、工作流程等,这些工具、脚本、工作流程等依赖于版本化的属性来驱动行为。对于所有这些,您现在有了新的工具可以使用,您如何使用它取决于您——我怀疑你们中的一些人会想出我们开发该功能时从未考虑过的可继承属性的巧妙应用。

注意事项

在我们结束今天的讨论之前,关于属性继承有几件事需要牢记。

升级旧的工作副本

回想一下,在上面的示例中,svn propget --show-inherited-props calc-trunk-wc 显示了calc-trunk-wc 上的属性以及在存储库中其父级上设置的属性。Subversion 通过在工作副本数据库中为工作副本的根目录维护一个继承属性缓存来完成对继承属性的查找 5。这个缓存会在工作副本更新时更新,例如在检出、更新或切换期间。当您通过“svn upgrade”命令升级旧格式的工作副本时,会创建此缓存,但不会填充。因此,请确保在升级后更新您的工作副本。

例如:糟糕,这是一个旧的工作副本!

>svn pg foo --verbose --show-inherited-props
svn: E155036: Please see the 'svn upgrade' command
svn: E155036: The working copy at 'C:\SVN\calc-trunk-wc'
is too old (format 29) to work with client version '1.8.0 (r1490375)' (expects format 31). You need to upgrade the working copy first.

我们将根据错误消息升级工作副本。

>svn upgrade

现在检查继承的属性。

>svn pg foo --verbose --show-inherited-props
Properties on '.':
  foo
    qux

哦,没错,缓存需要通过更新来填充!

>svn up
Updating '.':
At revision 478.

现在找到了继承的属性。

>svn pg foo --verbose --show-inherited-props
Inherited properties on '.',
from 'http://svn.example.com/repos':
  foo
    bar
Inherited properties on '.',
from 'http://svn.example.com/repos/calc':
  foo
    baz
Properties on '.':
  foo
    qux

最低要求

虽然您显然需要 1.8 Subversion 客户端,但 1.8 服务器是可选的。1.8 服务器在填充继承属性缓存或对 URL 使用 proplist/propget 子命令时可能会提供更好的性能。

授权

您只能从您有读取权限的存储库路径继承属性。如果您没有对给定路径的读取权限,它将显示为没有从该路径继承的属性。在这种情况下不会发出警告或错误。

工作副本内的继承

如上所述,继承属性缓存只知道工作副本根目录继承了哪些属性。这意味着本地更改或混合版本工作副本不会影响给定工作副本路径继承的内容。这里不是讨论这个问题的全部含义的地方,但请记住这个简单的规则,这样你就不会有任何意外:如果你依赖于拥有继承属性的最新值(例如来自存储库的根目录),请确保你的工作副本的根目录是最新的。

备注

  1. 经验丰富的用户可能会合理地抗议说,Subversion 已经有一个属性,它的影响可以超出目录的直接子目录,即svn:mergeinfo 属性。当然,你是完全正确的,svn:mergeinfo 是可继承的,但它是一个特殊情况,它有自己一套完善的规则,在讨论“通用”可继承属性时可以安全地忽略它。

  2. 这里使用--verbose 选项来提供格式良好的输出。

  3. 再次以svn:mergeinfo 为例外。

  4. 从 Subversion 1.8.0 开始,Subversion 解释为可继承的唯一保留属性是svn:auto-props(在本博客的第 2 部分中介绍)和svn:global-ignores(在本博客的第 3 部分中介绍)。在 Subversion 的未来版本中,期待使用继承属性构建更多功能(例如日志消息模板机制)。在此期间,请随意使用此功能。任何你想应用于整个存储库(或其大型子部分)的版本化元数据都可以轻松地存储在存储库根目录(或相应的子树)的属性中。

  5. 一般来说,Subversion 工作副本努力只在绝对必要时才联系存储库。这保留了在无法联系存储库时使用工作副本的能力,并且在所有其他条件相同的情况下,如果不需要联系存储库,则给定操作可能会更快。

  6. 您工作副本中的任何切换路径都算作单独的工作副本根目录,并将拥有自己的缓存。

关于作者

Paul Burba 是 Apache 软件基金会 Subversion 项目的提交者,过去九年一直在 Subversion 上工作。他是一名 Collabnet 的软件工程师,在家乡新罕布什尔州工作。当他不写代码时,通常可以被发现与侄子一起滑雪,与朋友一起骑山地自行车,或与妻子一起旅行。在遥远的过去,Paul 从新罕布什尔大学获得了商业学位。最近,他获得了波士顿大学的计算机科学硕士学位。