属性

我们已经详细讲述了Subversion存储和检索版本库中不同版本的文件和目录的细节,并且用了好几个章节来论述这个工具的基本功能。如果对于版本化的支持到此为止,从版本控制的角度来看Subversion已经完整了。

但不仅仅如此。

作为目录和文件版本化的补充,Subversion提供了对每一个版本化的目录和文件添加、修改和删除版本化的元数据的接口,我们用属性来表示这些元数据。我们可以认为它们是一个两列的表,附加到你的工作拷贝的每个条目上,映射属性名到任意的值。一般来说,属性的名称和值可以是你希望的任何值,限制就是名称必须是可读的文本,并且最好的一点是这些属性也是版本化的,就像你的文本文件内容,你可以像提交文本修改一样修改、提交和恢复属性修改,当你更新时也会接收到别人的属性修改—你不必为适应属性改变你的工作流程。

注意

Subversion自己保留了一组名称以svn:开头的属性,现在已经有了一些在用的属性,所以在你根据需要创建自定义属性时,需要避免这些前缀开头的名称,否则,Subversion的新版本可能会采用同名的属性来满足新的特性,而其含义可能会完全不同。

Properties show up elsewhere in Subversion, too. Just as files and directories may have arbitrary property names and values attached to them, each revision as a whole may have arbitrary properties attached to it. The same constraints apply—human-readable names and anything-you-want binary values. The main difference is that revision properties are not versioned. In other words, if you change the value of, or delete, a revision property, there's no way, within the scope of Subversion's functionality, to recover the previous value.

Subversion has no particular policy regarding the use of properties. It asks only that you not use property names that begin with the prefix svn:. That's the namespace that it sets aside for its own use. And Subversion does, in fact, use properties—both the versioned and unversioned variety. Certain versioned properties have special meaning or effects when found on files and directories, or they house a particular bit of information about the revisions on which they are found. Certain revision properties are automatically attached to revisions by Subversion's commit process, and they carry information about the revision. Most of these properties are mentioned elsewhere in this or other chapters as part of the more general topics to which they are related. For an exhaustive list of Subversion's predefined properties, see “Subversion Properties”一节.

In this section, we will examine the utility—both to users of Subversion and to Subversion itself—of property support. You'll learn about the property-related svn subcommands and how property modifications affect your normal Subversion workflow.

为什么需要属性?

就像Subversion使用属性保存其包含的文件、目录和修订版本的附加信息,你也会发现属性有一些类似的使用,你会发现如果在数据附近有个地方保存自定义元数据会非常有用。

Say you wish to design a web site that houses many digital photos and displays them with captions and a datestamp. Now, your set of photos is constantly changing, so you'd like to have as much of this site automated as possible. These photos can be quite large, so as is common with sites of this nature, you want to provide smaller thumbnail images to your site visitors.

Now, you can get this functionality using traditional files. That is, you can have your image123.jpg and an image123-thumbnail.jpg side by side in a directory. Or if you want to keep the filenames the same, you might have your thumbnails in a different directory, such as thumbnails/image123.jpg. You can also store your captions and datestamps in a similar fashion, again separated from the original image file. But the problem here is that your collection of files multiplies with each new photo added to the site.

Now consider the same web site deployed in a way that makes use of Subversion's file properties. Imagine having a single image file, image123.jpg, with properties set on that file that are named caption, datestamp, and even thumbnail. Now your working copy directory looks much more manageable—in fact, it looks to the casual browser like there are nothing but image files in it. But your automation scripts know better. They know that they can use svn (or better yet, they can use the Subversion language bindings—see “使用API”一节) to dig out the extra information that your site needs to display without having to read an index file or play path manipulation games.

Custom revision properties are also frequently used. One common such use is a property whose value contains an issue tracker ID with which the revision is associated, perhaps because the change made in that revision fixes a bug filed in the tracker issue with that ID. Other uses include hanging more friendly names on the revision—it might be hard to remember that revision 1935 was a fully tested revision. But if there's, say, a test-results property on that revision with the value all passing, that's meaningful information to have.

操作属性

The svn command affords a few ways to add or modify file and directory properties. For properties with short, human-readable values, perhaps the simplest way to add a new property is to specify the property name and value on the command line of the propset subcommand:

$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c
property 'copyright' set on 'calc/button.c'
$

But we've been touting the flexibility that Subversion offers for your property values. And if you are planning to have a multiline textual, or even binary, property value, you probably do not want to supply that value on the command line. So the propset subcommand takes a --file (-F) option for specifying the name of a file that contains the new property value.

$ svn propset license -F /path/to/LICENSE calc/button.c
property 'license' set on 'calc/button.c'
$

对于属性名称也有一些限制,属性名必须以一个字符、一个冒号(:)或下划线(_)开始,之后你可以使用数字,横线(-)和句号(.)。 [8]

In addition to the propset command, the svn program supplies the propedit command. This command uses the configured editor program (see “配置”一节) to add or modify properties. When you run the command, svn invokes your editor program on a temporary file that contains the current value of the property (or that is empty, if you are adding a new property). Then, you just modify that value in your editor program until it represents the new value you wish to store for the property, save the temporary file, and then exit the editor program. If Subversion detects that you've actually changed the existing value of the property, it will accept that as the new property value. If you exit your editor without making any changes, no property modification will occur:

$ svn propedit copyright calc/button.c  ### exit the editor without changes
No changes to property 'copyright' on 'calc/button.c'
$

We should note that, as with other svn subcommands, those related to properties can act on multiple paths at once. This enables you to modify properties on whole sets of files with a single command. For example, we could have done the following:

$ 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

还有一个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允许属性值为空,所有不能用propedit或者propset命令删除一个属性。例如,这个命令不会产生预期的效果:

$ 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
$

Remember those unversioned revision properties? You can modify those, too, using the same svn subcommands that we just described. Simply add the --revprop command line parameter and specify the revision whose property you wish to modify. Since revisions are global, you don't need to specify a target path to these property-related commands so long as you are positioned in a working copy of the repository whose revision property you wish to modify. Otherwise, you can simply provide the URL of any path in the repository of interest (including the repository's root URL). For example, you might want to replace the commit log message of an existing revision. [9] If your current working directory is part of a working copy of your repository, you can simply run the svn propset command with no target path:

$ 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'
$

注意,修改这些未版本化的属性的能力一定要明确的添加给版本库管理员(见“修正提交消息”一节)。因为属性没有版本化,如果编辑的时候不小心,就会冒丢失信息的风险,版本库管理员可以设置方法来防范这种意外,缺省情况下,修改未版本化的属性是禁止的。

提示

Users should, where possible, use svn propedit instead of svn propset. While the end result of the commands is identical, the former will allow them to see the current value of the property that they are about to change, which helps them to verify that they are, in fact, making the change they think they are making. This is especially true when modifying unversioned revision properties. Also, it is significantly easier to modify multiline property values in a text editor than at the command line.

属性和 Subversion 工作流程

现在你已经熟悉了所有与属性相关的svn子命令,让我们看看属性修改如何影响Subversion的工作流。我们前面提到过,文件和目录的属性是版本化的,这一点类似于版本化的文件内容。后果之一,就是Subversion具有了同样的机制来合并—用干净或者冲突的方式—其他人的修改应用到你的修改。

As with file contents, your property changes are local modifications, made permanent only when you commit them to the repository with svn commit. Your property changes can be easily unmade, too—the svn revert command will restore your files and directories to their unedited states—contents, properties, and all. Also, you can receive interesting information about the state of your file and directory properties by using the svn status and svn diff commands.

$ svn status calc/button.c
 M     calc/button.c
$ svn diff calc/button.c
Property changes on: calc/button.c
___________________________________________________________________
Name: copyright
   + (c) 2006 Red-Bean Software

$

注意status子命令显示的M在第二列而不是在第一列,这是因为我们修改了calc/button.c的属性,而不是它的文本内容,如果我们都修改了,我们也会看到M出现在第一列(见“查看你的修改概况”一节)。

You might also have noticed the nonstandard way that Subversion currently displays property differences. You can still run svn diff and redirect the output to create a usable patch file. The patch program will ignore property patches—as a rule, it ignores any noise it can't understand. This does, unfortunately, mean that to fully apply a patch generated by svn diff, any property modifications will need to be applied by hand.

自动设置属性

属性是Subversion一个强大的特性,成为本章和其它章讨论的许多Subversion特性的关键组成部分—文本区别和合并支持、关键字替换、新行的自动转换等等。但是为了从属性得到完全的利益,他们必须设置到正确的文件和目录。不幸的是,在日常工作中很容易忘记这一步工作,特别是当没有设置属性不会引起明显的错误时(至少相对与未能添加一个文件到版本控制这种操作),为了帮助你在需要添加属性的文件上添加属性,Subversion提供了一些简单但是有用的特性。

Whenever you introduce a file to version control using the svn add or svn import commands, Subversion tries to assist by setting some common file properties automatically. First, on operating systems whose filesystems support an execute permission bit, Subversion will automatically set the svn:executable property on newly added or imported files whose execute bit is enabled. (See “文件的可执行性”一节 later in this chapter for more about this property.)

Secondly, Subversion tries to determine the file's MIME type. If you've configured a mime-types-files runtime configuration parameter, Subversion will try to find a MIME type mapping in that file for your file's extension. If it finds such a mapping, it will set your file's svn:mime-type property to the MIME type it found. If no mapping file is configured, or no mapping for your file's extension could be found, Subversion runs a very basic heuristic to determine if the file contains nontextual content. If so, it automatically sets the svn:mime-type property on that file to application/octet-stream (the generic “this is a collection of bytes” MIME type). Of course, if Subversion guesses incorrectly, or if you wish to set the svn:mime-type property to something more precise—perhaps image/png or application/x-shockwave-flash—you can always remove or edit that property. (For more on Subversion's use of MIME types, see “文件内容类型”一节 later in this chapter.)

Subversion also provides, via its runtime configuration system (see “运行配置区”一节), a more flexible automatic property setting feature that allows you to create mappings of filename patterns to property names and values. Once again, these mappings affect adds and imports, and can not only override the default MIME type decision made by Subversion during those operations, but can also set additional Subversion or custom properties, too. For example, you might create a mapping that says that any time you add JPEG files—ones whose names match the pattern *.jpg—Subversion should automatically set the svn:mime-type property on those files to image/jpeg. Or perhaps any files that match *.cpp should have svn:eol-style set to native, and svn:keywords set to Id. Automatic property support is perhaps the handiest property related tool in the Subversion toolbox. See “配置”一节 for more about configuring that support.



[8] 如果你熟悉XML,其实这就是XML的"Name"语法的ASCII子集。

[9] 修正提交日志信息的拼写错误,文法错误和“简单的错误”是--revprop选项最常见用例。