This text is a work in progress—highly subject to change—and may not accurately describe any released version of the Apache™ Subversion® software. Bookmarking or otherwise referring others to this page is probably not such a smart idea. Please visit http://www.svnbook.com/ for stable versions of this book.
我们已经详细地描述了 Subversion 如何存放和检索存放在仓库中的不同 版本的文件和目录, 介绍这些最基本的功能用了一整章的篇幅. 如果 Subversion 对版本控制的支持就到此为止, 从版本控制的角度来看它的功能已经很完整了.
但 Subversion 并没有停下脚步.
作为目录和文件版本控制的补充, Subversion 提供了为每一个文件和目录添加, 修 改和删除版本化元数据的接口. 我们把这些元数据称为 属性 (properties), 属性可看作是一张两列的表格, 附加到 工作副本的每个项目上, 表格把属性的名字映射到任意值. 一般来说, 属性的名字 和值可以是任意的, 唯一的要求是属性名只能使用 ASCII 字符. 属性最好的地方 是它们也是被版本控制的对象, 就像文件的内容那样, 用户可以修改, 提交和撤销 属性的修改. 用户执行提交和更新操作时, 属性的修改也会被发送和接收— 用户的工作流程不会因为属性的加入而发生变化.
注意 | |
---|---|
Subversion 保留了一组名字以 |
除了文件和目录, 属性还可以出现在其他地方, 每一个版本号都是一个实体, 可以在它上面附加任意的属性, 唯一的要求是属性名只能使用 ASCII 字符. 同文件和目录的属性相比, 最大的不同是版本号的属性不会被版本控制, 也就是 说如果版本号的属性被删除或修改了, Subversion 没有能力把它们恢复到以前 的值.
关于属性的使用, Subversion 并没有很特别的策略, 唯一的要求是用户不
要使用以 svn:
开始的属性名, 这是保留给 Subversion
使用的名字空间, Subversion 使用的属性包括版本化的和未版本化的. 文件和
目录上特定的版本化属性具有特殊的意义或效果, 或提供了版本号的一些信息.
在提交时, 特定的版本号属性被自动地附加到版本号上, 属性包含了与版本号
有关的信息. 大多数属性会在谈到相关的主题时再介绍, Subversion 的预定义
属性的完整列表见 “Subversion 的保留属性”一节.
注意 | |
---|---|
虽然 Subversion 自动地把属性 ( |
本节将介绍 svn—不仅是对 Subversion 用户, 也对 Subversion 自身—对属性的支持. 读者将会学到与属性相关的 svn 子命令, 以及属性如何影响用户的工作检验.
Subversion 使用属性存放和文件, 目录, 版本号相关的额外信息, 读者 可能也会发现属性的类似用法. 你会发现, 如果在数据附近能有个地方保存 自定义元数据将会是一项非常有用的特性.
假设你想要设计一个网站, 其中存放了很多数字照片, 在显示时会给照片 加上标题和日期. 因为你的照片经常发生变化, 所以你希望网站能够尽量地自动 处理由于照片变动而产生的影响. 照片可以很大, 你希望在网站上可以显示照片 的缩略图.
你可以用传统的文件实现缩略图, 也就是说你可以把照片
image123.jpg
及其缩略图
image123-thumbnail.jpg
放在同一个目录里. 如果你
希望照片及其缩略图能使用相同的文件名, 也可以把缩略图放在不同的目录里,
例如 thumbnails/image123.jpg
. 你可以按照类似的方
法存放标题和日期. 这里最大的问题是每增加一个新图片, 网站的文件数量都
会成倍地增加.
现在考虑如果利用 Subversion 的文件属性来部署网站. 设想有一个图片
文件 image123.jpg
, 带有属性
caption
, datestamp
和
thumbnail
. 使用属性后的工作副本看起来更容量管理
—实际上, 普通的浏览器只能看到图片文件, 但是你的自动化管理脚本
可以知道得更多. 脚本可以使用 svn (更好的做法是用
Subversion 的语言绑定—见 “使用 API”一节)
获取图片的属性信息, 而不必读取索引文件或处理路径.
注意 | |
---|---|
Subversion 对属性的名字和值有一些限制, 如果属性的值很大, 或者在 单个的文件或目录上设置了很多的属性, 对于这两种情况 Subversion 处理 起来非常笨拙. Subversion 通常会把单个项目的所有属性及其值同时加载 到内存中, 如果属性过多, 性能就会受到影响, 甚至导致命令失败. |
自定义版本号属性也经常用到, 一种常见的用法是为版本号添加一个包含
问题跟踪 ID 的属性, 表示该版本号修复了这个问题. 其他一些用法还可以
是为版本号附加一个更友好的名字—人们很难记住版本号 1935 是一个
经过充分测试的版本, 但是如果给版本号 1935 添加一个属性
test-results
, 属性值是
all passing
, 这样一来就方便多了. 用户可以通过
svn commit 的选项 --with-revprop
为新提交的版本号附加属性 test-results
:
$ svn commit -m "Fix up the last remaining known regression bug." \ --with-revprop "test-results=all passing" Sending lib/crit_bits.c Transmitting file data . Committed revision 912. $
命令 svn 提供了几种用于添加或修改文件和目录 属性的方法. 如果属性的值比较短, 而且是人类可读的, 那么添加新属性的 最简单的方法是在子命令 svn propset 的命令行参 数上指定属性名和值:
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c property 'copyright' set on 'calc/button.c' $
Subversion 对于属性值给予了很大的灵活性, 如果属性值包含多行文本,
甚至是二进制格式, 此时用户就不太可能把值写在命令行参数上, 为了解决
这个问题, svn propset 支持选项
--file
(-F
), 该选项指定了一个包含
属性值的文件的名字.
$ svn propset license -F /path/to/LICENSE calc/button.c property 'license' set on 'calc/button.c' $
对属性名有一些限制条件, 属性名必须以字母, 冒号 (:
)
或下划线 (_
) 开始, 接下来的字符, 除了前面介绍的, 还可
以用数字, 连字符 (-
), 句点 (.
).
[12]
除了 propset, svn 还提供了 子命令 propedit. propedit 使用 预先配置的外部编辑器 (见 “通用配置选项”一节) 来添加或修改属性. 执行 svn propedit 时, 命令在一个临时文件上打开 编辑器, 临时文件的内容是属性的当前值 (如果是添加新属性, 内容就是空的), 然后用户就可以按照自己的需要在编辑器里修改属性值, 修改完成后保存临时 文件, 最后退出编辑器. 退出编辑器后, 如果 Subversion 检测到属性原来的 值被修改了, 它就把修改后的值当作属性的新值. 如果用户没有修改便退出 编辑器, 属性值就保持不变:
$ svn propedit copyright calc/button.c ### exit the editor without changes No changes to property 'copyright' on 'calc/button.c' $
应该注意到, 和 svn 的其他子命令一样, 属性操作 可以同时施加到多个路径上, 这就允许用户用一个命令修改整个文件集合的属性, 例如我们可以这样做:
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/* property 'copyright' set on 'calc/Makefile' property 'copyright' set on 'calc/button.c' property 'copyright' set on 'calc/integer.c' … $
如果用户不能方便地获取属性值, 那么属性的添加和删除就没什么大用处, 所以 svn 提供了两个子命令用于显示文件和目录上的 属性名和值. 命令 svn proplist 列出指定路径上的属性 的名字, 一旦知道了属性名, 就可以用命令 svn propget 分别地获取各个属性的值, 它根据指定的属性名和一个路径 (或多个路径) 打印 出属性的值.
$ svn proplist calc/button.c Properties on 'calc/button.c': copyright license $ svn propget copyright calc/button.c (c) 2006 Red-Bean Software
执行命令 svn proplist 时如果加上选项
--verbose
(-v
), 命令就会同时列出
所有属性的名字和值.
$ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software license ================================================================ Copyright (c) 2006 Red-Bean Software. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the recipe for Fitz's famous red-beans-and-rice. …
最后一个与属性相关的子命令是 propdel. 因为
Subversion 允许为属性设置空值, 所以用户不能想当然地认为用
svn propedit 和 svn propset
把属性值设置成空值, 就能实现完全删除属性的效果, 比如说下面的命令不会产
生用户想要的效果 (用户想要的效果是删除属性 license
)
:
$ svn propset license "" calc/button.c property 'license' set on 'calc/button.c' $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software license $
为了完全删除属性, 需要使用子命令 propdel, 它的使用语法和其他属性命令类似:
$ svn propdel license calc/button.c property 'license' deleted from 'calc/button.c'. $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software $
还记得那些非版本化的版本号属性吗? 用户也可以用我们刚刚介绍过的
svn 的子命令去修改它们, 只要加上选项
--revprop
和欲修改的版本号. 因为版本号是全局的, 所以
只要用户已经位于欲修改的版本号的工作副本中, 就不需要为命令指定目标路径,
否则的话, 可以在命令行上提供目标路径的 URL 参数. 例如, 用户可能想修改
一个已存在的版本号的提交日志,[13] 如果你的当前工作目录是工作副本的一
部分, 可以不带目标路径地执行命令 svn propset:
$ svn propset svn:log "* button.c: Fix a compiler warning." -r11 --revprop property 'svn:log' set on repository revision '11' $
即使用户没有检出仓库的工作副本, 仍然可以通过提供仓库的根 URL 来 修改属性:
$ svn propset svn:log "* button.c: Fix a compiler warning." -r11 --revprop \ http://svn.example.com/repos/project property 'svn:log' set on repository revision '11' $
需要注意的是只有在仓库管理员配置后用户才能修改非版本化属性 (见 “修正提交日志消息”一节). 这是因为如果属性是非 版本化的, 用户一不小心就有可能弄丢信息. 仓库管理员可以采取一定的措施 防止信息丢失, 在默认情况下, 修改非版本化属性是被禁止的.
提示 | |
---|---|
如果可以的话, 用户应该尽量使用 svn propedit, 而不是 svn propset. 虽然这两个命令的执行结果是 一样的, 但是 svn propedit 允许用户看到将要被修改 的属性的当前值, 这可以帮助他们确认自己是否正在按照自己想要的那样 操作. 另外, 在编辑器中修改具有多行文本的属性, 要比在命令行上修改方便 得多. |
既然读者已经熟悉了所有与属性相关的 svn 子命令, 现在来看属性修改将会如何影响 Subversion 的工作流程. 我们已经说过, 文件和目录的属性是被版本控制的, 就像文件内容那样, 因此 Subversion 也 支持属性的合并—或干净利落地, 或带有冲突.
和文件内容一样, 属性修改一开始只是本地的, 只有用 svn commit 提交后, 属性的修改才会持久化. 属性的修改 也能轻易地撤消—命令 svn revert 可以撤消所有 文件和目录的本地修改, 包括属性修改, 内容修改, 以及其他所有的本地修改. 你也可以用 svn status 和 svn diff 获取文件和目录的属性状态.
$ svn status calc/button.c M calc/button.c $ svn diff calc/button.c Property changes on: calc/button.c ___________________________________________________________________ Added: copyright ## -0,0 +1 ## +(c) 2006 Red-Bean Software $
注意, 子命令 status 把 M
显示
在了第二列, 而不是第一列, 这是因为我们修改的是
calc/button.c
的属性, 而不是内容. 如果我们同时修改
了内容和属性, 我们就会同时在第一列和第二列看到 M
(我们在 “查看修改的整体概述”一节 介绍了
svn status).
读者可能已经注意到了 Subversion 的属性差异输出并不是一种标准的 格式, 用户仍然可以用 svn diff 并把它的输出重定向 到补丁文件里, 但 patch 会忽略属性的补丁— patch 的一条规则是忽略所有不能理解的内容, 这就意味 着如果用户用的是 patch, 为了完整地打上 svn diff 生成的补丁, 用户必须手工地打上和属性相关的 修改.
Subversion 1.7 从两个方面改善了这个问题, 首先, 属性的差异输出至少 是机器可读的—这是对 1.7 版之前的属性显示的改进. 然后 Subversion 1.7 引入了新命令 svn patch, 专门用来处理 svn diff 的输出中带有的额外信息, 并把这些信息应用 到工作副本中. 对于属性来说, 使用 Subversion 1.7 及以后版本的 svn diff 生成的补丁, 如果其中包含了属性差异, 那么 svn patch 可以自动地把这些差异应用到工作副本. 关于 svn patch 的更多信息, 见 svn 参考手册—Subversion 命令行客户端 的 svn patch.
注意 | |
---|---|
svn diff 在报告属性的变化时有一个例外, 那就是
特殊的 |
Subversion 1.8 引入了继承属性这个概念. 将一个属性设置成可继承的 并没有什么很特别的地方, 实际上, 所有版本化的属性都是可继承的! 1.8 前 的版本化属性和 1.8 后的版本化属性的主要区别是后者支持在一个目标路径 的 父路径 (parents) 上搜索 属性, 即使这些父路径在工作副本里不存在.
有些命令可以显示出一般的属性继承, 首先 svn proplist
和 svn propget 可以检索 URL 的或工作副本路径的父路径
上的所有属性, 方法是带上选项 --show-inherited-props
.
读者可能会觉得这是选项 --recursive
的反面—选项
--recursive
向 “下” 递归到目标的子目录里,
而 --show-inherited-props
是向 “上” 看
目标的父目录. 命令 svnlook propget 和
svnlook proplist 按照类似的方法使用选项
--show-inherited-props
.
举个例子, 在工作副本的根目录递归地调用 propget
, 发现子命令的目标路径及其中的一个子目录 site
都设置了属性 svn:auto-props
:
$ svn pg svn:auto-props --verbose -R . Properties on '.': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native Properties on 'site': svn:auto-props *.html = svn:eol-style=native
如果我们把子目录 site
作为子命令的目标路径,
然后使用选项 --show-inherited-props
, 我们将会看到属性
svn:auto-props
存在于目标路径 和
它的父路径上, 父路径的属性是 “被继承的”:
$ svn pg svn:auto-props --verbose --show-inherited-props site Inherited properties on 'site', from '.': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native Properties on 'site': svn:auto-props *.html = svn:eol-style=native
在上一个例子里, 工作副本的根目录对应仓库的根目录, 但即使没有这种
对应, 属性也可以从工作副本的外面继承. 现在检出上一个例子的
site
目录, 使它成为工作副本的根目录:
$ svn co http://svn.example.com/repos site-wc A site-wc/publish A site-wc/publish/ch2.html A site-wc/publish/news.html A site-wc/publish/ch3.html A site-wc/publish/faq.html A site-wc/publish/index.html A site-wc/publish/ch1.html U site-wc Checked out revision 19. $ cd site-wc
当我们在一条工作副本路径上检查继承的属性时将会看到, 一个属性继承 自工作副本里的父目录, 一个属性继承自仓库里的父路径, 该路径在工作副本 的根目录的 “上层”:
$ svn pg svn:auto-props --verbose --show-inherited-props publish Inherited properties on 'publish', from 'http://svn.example.com/repos': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native Inherited properties on 'publish', from '.': svn:auto-props *.html = svn:eol-style=native
警告 | |
---|---|
用户只能从他拥有读权限的仓库路径上继承属性—见 “内建的认证与授权”一节 和 “授权选项”一节. 如果用户对某条 父路径没有读权限, 看起来的效果就像是父路径上没有设置属性. |
前面已经说过, svnlook proplist 和
svnlook propget 也支持选项
--show-inherited-props
, 但它们不是以工作副本路径或
URL 作为目标路径, 而是以仓库的路径作为目标路径:
$ svnlook pg repos svn:auto-props /site/publish --show-inherited-props -v Inherited properties on '/site/publish', from '/': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native Inherited properties on '/site/publish', from '/site': svn:auto-props *.html = svn:eol-style=native
当工作副本被首次检出或者更新时, 从工作副本根目录上层继承而来的属性 会被缓存在工作副本的管理数据库里, 这样的话在查看继承的属性时就不用再 访问仓库了, 同时也允许那些不要求访问仓库的子命令 (例如 svn add ) 在保持 “无连接” 的同时, 仍然可以访问到从工作 副本之外的路径继承而来的属性. 但同时也意味着在最近一次更新之后, 来自工 作副本根目录上层的继承属性可能已经发生了变化, 使得本地缓存变成过时了的. 所以如果用户要求继承的属性始终是最新的, 最好更新一下工作副本或直接询问 仓库.
到这里读者可能会想 “看起来挺有趣的, 但这有什么好处呢?
” 对于属性继承本身来说是没多大用处, 在 1.8 之前, Subversion
所有的保留属性 svn:*
(还可能包括所有的用户自定
义属性) 都只能应用到它们所在的路径上, 至多再加上直接子路径
[14]. Subversion 使用继承属性完成另一些更有趣的事情, 比如说用
属性 svn:auto-props
设置自动属性, 用属性
svn:global-ignores
实现全局的忽略模式—
关于这些特殊属性的更多信息和使用方法, 见
“自动属性设置”一节 和
“忽略未被版本控制的项”一节.
提示 | |
---|---|
目前可继承的属性中起主要作用的是 |
属性是 Subversion 最强大的特性之一, 它是本章和其他章节介绍的众多 Subversion 特性—文本差异比较, 合并支持, 关键字替换和换行符转换 等—的关键基础. 为了充分发挥属性的作用, 它们必须被设置到正确的 文件和目录上, 不幸的是, 这个步骤在日常工作中常常被人遗忘, 尤其是因为 即使属性设置不当通常也不会造成很明显的错误 (至少和文件添加失败比起 来, 不是很明显). 为了帮助用户更好地使用属性, Subversion 提供了几个 简单但很有用的特性.
每当用户使用 svn add 和 svn import
向仓库添加文件时, Subversion 自动地在文件上设置一些常见的
属性. 首先, 如果操作系统的文件系统支持可执行权限位并且文件具有可执行
权限, Subversion 就自动在文件上设置 svn:executable
属性 (关于这个属性的更多信息, 见
“文件的可执行性”一节).
然后, Subversion 会试图判断文件的 MIME 类型. 如果用户为
mime-types-files
设置了一个运行时配置参数, Subversion
就会尝试根据文件的后缀名为文件搜索一个对应的 MIME 类型映射, 若找到的话,
它就把文件的 svn:mime-type
属性设置成找到的 MIME
类型. 如果用户没有为 mime-types-files
设置运行时
配置参数, 或者根据后缀名没有找到对应的类型映射, Subversion 就使用启发
式的算法来判断文件的 MIME 类型. 取决于编译时的配置, Subversion 1.7
可以利用文件扫描函数库[15] 检测文件的类型. 如果前面的都失败了, Subversion 就
使用它非常基本的启发式算法来判断文件是否包含非文本数据, 如果是, 就自动
地把文件的 svn:mime-type
属性设置成
application/octet-stream
(最一般的 MIME 类型, 表示
“这是字节的集合”). 当然, 如果 Subversion 的判断不正确,
又或者是用户想把 svn:mime-type
设置成更精确的值
—比如 image/png
或
application/x-shockwave-flash
—可以自由地修改或删除
属性 svn:mime-type
(关于 Subversion 如何使用 MIME
类型的更多信息, 见本章后面的
“文件内容类型”一节).
注意 | |
---|---|
有很多文件使用的是 UTF-16 编码, 虽然在语义上文件的内容是纯文本 的, 但是 UTF-16 使用的字节在 ASCII 字符的范围之外, 因此 Subversion 更倾向于把它们归类为二进制文件, 用户在给这些文件进行差异比较, 合并 和关键字替换时也会因此遇到一些小麻烦. |
借助运行时配置系统 (见 “运行时配置区域”一节),
Subversion 提供了一种更加灵活的自动属性设置功能, 它允许用户创建文件名
模式到属性名和值的映射. 再说一次, 这些映射会影响
svn add 和 svn import, 除了会
覆盖由 Subversion 判断出的默认 MIME 类型, 还可能添加额外的属性或自定义
属性. 例如, 用户想创建一个映射, 这个映射是说每次添加一个 JPEG 文件时
—文件的名字符合模式 *.jpg
—Subversion
都应该自动地把这个文件的 svn:mime-type
属性设置为
image/jpeg
. 又或者说匹配模式 *.cpp
的文件都应该把 svn:eol-style
设置成 native
, 把 svn:keywords
设置成 Id
. 关于运行时配置如何支持自动属性的更多细节, 见
“通用配置选项”一节.
虽然借助运行时配置系统来支持自动属性设置非常方便, 但 Subversion
管理员可能更希望看到这样一种情况: 当客户端在一个从特定服务器检出的
工作副本上工作时, 可以自动地顾及到某些属性定义. Subversion 1.8 及其
之后的客户端版本通过可继承属性 svn:auto-props
实现这个功能.
属性 svn:auto-props
可以像运行时配置系统那样,
自动地为新增的文件设置属性, 属性 svn:auto-props
的值应该和运行时配置选项 auto-props
的值相同 (也
就是任意数量的键值对, 格式是
FILE_PATTERN = PROPNAME=VALUE[;PROPNAME=VALUE ...]). 和运行时选项
auto-props
一样, 如果使用了选项
--no-auto-props
, 属性 svn:auto-props
就会被忽略, 但是有所不同的是, 即使配置选项
enable-auto-props
被设置为 no
,
属性 svn:auto-props
也不会被禁止.
举例来说, 你检出了主干的工作副本, 想在其中添加一个新文件 (假设 运行时配置系统禁止了自动属性):
$ svn st ? calc/data.c $ svn add calc/data.c A calc/data.c $ svn proplist -v calc/data.c Properties on 'calc/data.c': svn:eol-style native
可以看到, 当 data.c
被版本控制后, 文件自动
设置了属性 svn:eol-style
. 因为运行时配置选项
auto-props
是禁止了的, 所以属性
svn:auto-props
肯定来自 data.c
的
父路径. 执行带上选项 --show-inherited-props
的命令
svn propget 可以看到, 事实的确是如我们所想的那样:
$ svn propget svn:auto-props --show-inherited-props -v calc Inherited properties on 'calc', from 'http://svn.example.com/repos': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native
属性 svn:global-ignores
及其对应的运行时配置
选项 global-ignores
是一起起作用, 但属性
svn:auto-props
和运行时选项
auto-props
的关系就不这样, 如果运行时选项
auto-props
在一个模式上设置了一个自动属性, 而
属性 svn:auto-props
也在 同一个
模式上设置了自动属性, 那么属性的设置就会覆盖运行时配置选项的设置.
从一个路径继承而来的自动属性 [16]也只会覆盖从其他路径继承的 同一个 模式.
覆盖的先后顺序是:
在 svn:auto-props
上定义的, 针对某一模式的
自动属性会覆盖运行时配置选项 auto-props
上设置
的同一模式的自动属性.
对于一个给定的模式而言, 如果它的自动属性继承自多个父路径的
svn:auto-props
属性, 那么在路径上最近的父路径
的自动属性会覆盖其中父路径.
对一个给定的模式而言, 如果在路径的 svn:auto-props
属性上显式地设置了一个自动属性, 那它就会覆盖从其他路径
继承而来的相同模式上的自动属性.
举例来说, 假设你有一个如下所示的运行时配置:
[miscellany] enable-auto-props = yes [auto-props] *.py = svn:eol-style=CR *.c = svn:eol-style=CR *.h = svn:eol-style=CR *.cpp = svn:eol-style=CR
你想添加 calc
目录中的三个文件:
$ svn st ? calc/data-binding.cpp ? calc/data.c ? calc/editor.py
先看一下 calc
的 svn:auto-props
属性:
$ svn propget svn:auto-props -v --show-inherited-props calc Inherited properties on 'calc', from 'http://svn.example.com/repos': svn:auto-props *.py = svn:eol-style=native *.c = svn:eol-style=native *.h = svn:eol-style=native Inherited properties on 'calc', from '.': svn:auto-props *.py = svn:eol-style=native *.c = svn:keywords=Author Date Id Rev URL
添加这三个文件, 然后检查它们的自动属性:
$ svn add calc --force A calc/data-binding.cpp A calc/data.c A calc/editor.py
文件 data-binding.cpp
只有一个匹配的模式,
也就是运行时配置选项里的 *.cpp = svn:eol-style=CR
,
显然文件的属性 svn:eol-style
被设置为 CR
:
$ svn proplist -v calc/data-binding.cpp Properties on 'calc/data-binding.cpp': svn:eol-style CR
文件 editor.py
既匹配运行时配置选项里的一
条模式, 也匹配属性 svn:auto-props
里的模式, 根据前
面介绍的覆盖顺序, 显式设置在 calc
上的属性值
(*.py = svn:eol-style=native
) 的优先级较高, 所以
属性 svn:eol-style
被设置为 native
:
$ svn proplist -v calc/editor.py Properties on 'calc/editor.py': svn:eol-style native
文件 data.c
同时匹配运行时配置选项和继承属性
svn:auto-props
的模式. 自动属性
svn:keywords
只被定义了一次, 在 calc
上定义, 所以 data.c
自动获取了该属性.
calc
上的 svn:auto-props
没有
为 svn:eol-style
定义值, 所以最近的父路径
http://svn.example.com/repos
提供了这个值:
$ svn proplist -v calc/data.c Properties on 'calc/data.c': svn:eol-style native svn:keywords Author Date Id Rev URL
警告 | |
---|---|
自动属性的覆盖只发生在 相同的 模式上, 如果
新增的文件同时匹配多个模式, 那就无法确定最终应用的是哪一个自动属性.
比如说用户想把文件 *.c* = svn:eol-style=native *.cpp = svn:eol-style=native;svn:keywords=Author Date Id Rev URL 因为 |
svn:auto-props
最后一个需要注意的地方是它 (以
及类似的 svn:global-ignores
, 见
“忽略未被版本控制的项”一节) 只是向理解属性
的客户端工具提供了一个建议, 较老的客户端会忽略这些属性, 选项
--no-auto-props
会忽略它们, 用户可能会选择手动地修改
或删除自动属性—有很多方法可以旁路掉包含在 svn:auto-props
里的推荐属性. 因此, 管理员仍然需要使用钩子脚本验证文件和
目录上的属性是否符合管理员的策略, 并拒绝与策略不兼容的提交 (钩子脚本见
“忽略未被版本控制的项”一节).
本节将对 Subversion 所有的保留属性做一个简单的总结, 包括版本化的 的属性 (和文件, 目录关联) 与非版本化的属性 (和版本号关联).
这些是 Subversion 保留给自己用的版本化属性:
svn:auto-props
该属性包含了一系列的自动属性定义, 如果被设置在一个目录上, 那么自动属性定义会应用到目录内的所有文件, 见 “自动属性设置”一节.
svn:executable
如果该属性被设置到一个文件上, 那客户端就会给 Unix 工作副本里 的文件设置上可执行权限, 见 “文件的可执行性”一节.
svn:mime-type
如果属性出现在一个文件上, 那么属性值指出了文件的 MIME 类型, 当更新时, 属性可以帮助客户端判断是否可以安全地对文件进行基于行 的合并操作. 另外, 当用户通过网页浏览器获取文件时, 该属性还会影 响文件的具体行为. 更多的信息参考 “文件内容类型”一节.
svn:ignore
如果该属性出现在一个目录上, 属性值是一个未被版本化的文件 模式列表, 符合模式的文件会被 svn status 和 其他子命令忽略, 见 “忽略未被版本控制的项”一节.
svn:global-ignores
如果该属性出现在一个目录上, 属性值是一个未被版本化的文件
模式列表, 符合模式的文件会被 svn status 和
其他子命令忽略, 但是和 svn:ignore
不同的是,
这些模式会应用到目录内 所有的 子目录及其
子文件, 而不仅仅是目录的直接子文件, 见
“忽略未被版本控制的项”一节.
svn:keywords
如果该属性出现在一个文件上, 属性的值指出了客户端应该如何 扩展文件内的特定关键字, 见 “关键字替换”一节.
svn:eol-style
如果该属性出现在一个文件上, 则属性的值指出了客户端应该如何 处理工作副本和导出目录里的文件的行终止符, 见 “行结束标记”一节 和 svn export.
svn:externals
如果该属性出现在一个目录上, 则属性的值是一个包含了多个路径 和 URL 的列表, 这些路径和 URL 都是客户端需要检出的内容, 见 “外部定义”一节.
svn:special
如果该属性出现在一个文件上, 则表示该文件不是一个普通的文件, 可能是一个符号链接或其他特殊的对象[17]
svn:needs-lock
如果该属性出现在一个文件上, 客户端就会把工作副本里的这个 文件设置成只读, 也就是提醒用户在编辑文件之前需要加锁, 见 “锁通信”一节.
svn:mergeinfo
Subversion 使用该属性跟踪合并信息, 更多的细节见 “合并信息和预览”一节, 除非你 真得 知道自己在做什么, 否则不要 编辑该属性.
下面是保留给 Subversion 使用的未版本化的 (或版本号) 属性, 它们中 的大部分都会出现在仓库的每个版本号上, 属性携带了关于修改的起因与 本质.
svn:author
如果设置了该属性, 则属性包含了创建此版本号用户名, 如果没有该属性, 那么版本号是匿名提交的.
svn:autoversioned
如果设置了该属性, 则说明版本号是通过自动版本化特性创建的, 见 “自动版本控制”一节.
svn:date
包含了版本号创建时的 UTC 时间, 使用 ISO 8601 格式, 时间来自 服务器 的机器时钟, 而不是客户 端的时钟.
svn:log
包含了描述版本号的日志消息.
Subversion 的某些辅助工具—svnrdump 和 svnsync—也会使用未版本化的属性完成记帐工作, 这些属性只会出现在仓库的版本号 0 上, 关于 svnrdump 和 svnsync 的更多信息, 见 第 5 章 仓库管理. 下面是由 svnrdump 和 svnsync 创建并管理的属性.
svn:rdump-lock
为 svnrdump load 访问仓库临时施加互斥 性, 通常只有在 svnrdump load 活动时— 或者在 svnrdump 不能干净地与仓库断开连接时 —该属性才会被观察到 (只有当这个属性出现在版本号 0 上时, 它才是有意义的).
svn:sync-currently-copying
包含了源仓库中已经被 svnsync 镜像备份 的版本号 (只有当这个属性出现在版本号 0 上时, 它才是有意义的).
svn:sync-from-uuid
包含了由 svnsync 创建的镜像的源仓库的 UUID (只有当这个属性出现在版本号 0 上时, 它才是有意义的).
svn:sync-from-url
包含了由 svnsync 创建的镜像的源仓库目录 的 URL (只有当这个属性出现在版本号 0 上时, 它才是有意义的).
svn:sync-last-merged-rev
包含了最近一次被成功地镜像备份的源仓库的版本号 (只有当这 个属性出现在版本号 0 上时, 它才是有意义的).
svn:sync-lock
为 svnsync 的镜像操作临时添加仓库访问 的互斥性, 通常只有在 svnsync 活动时— 或者在 svnsync 不能干净地与仓库断开连接时, 只有当这个属性出现在版本号 0 上时, 它才是有意义的).
[12] 如果读者熟悉 XML, 就会发现这很像 XML “Name” 语法的 ASCII 子集.
[13] 修改提交日志的拼写错误,
语法问题和其他的一般性错误可能是 --revprop
最常见
的应用场景.
[14] 有一个例外是 svn:mergeinfo
属性,
它是可继承的—见
“合并信息和预览”一节
[15] 当前比较常用的函数库是 libmagic
[16] 用户只能从他拥有读权限
路径上继承属性, 所以说如果管理员在较高层的父路径上 (例如仓库的
根目录) 设置了属性 svn:auto-props
, 他就应该
确保所有用户都能读取该路径或者期望的自动属性设置不会失效.
[17] 在写到这里时, 符号链接是已知的唯一一个 “特殊” 对象, 在以后 的版本里可能会出现更多种类的特殊对象.