本手册是为描述 Subversion 1.2 版本而编写的。如果您正在运行 Subversion 的较新版本,我们强烈建议您访问 https://svnbooks.subversion.org.cn/ 并查阅与您 Subversion 版本相符的版本。
我们已经详细介绍了 Subversion 如何在其存储库中存储和检索文件的各种版本和目录的版本。整章内容都致力于 Subversion 提供的最基本的功能。如果版本控制的支持仅此而已,那么从版本控制的角度来看,Subversion 仍然是完整的。但它并没有止步于此。
除了对您的目录和文件进行版本控制外,Subversion 还提供接口来添加、修改和删除您每个版本化目录和文件上的版本化元数据。我们将此元数据称为 属性,可以将其视为双列表,将属性名称映射到附加到工作副本中每个项目上的任意值。通常来说,属性的名称和值可以是您想要的任何东西,但要受限于名称必须是人类可读的文本。这些属性最棒的地方在于它们也是版本化的,就像文件中的文本内容一样。您可以修改、提交和还原属性更改,就像提交文本更改一样。当您更新工作副本时,您会收到其他人的属性更改。
在本节中,我们将研究属性支持对 Subversion 用户和 Subversion 本身的效用。您将了解与属性相关的 svn 子命令,以及属性修改如何影响您的正常 Subversion 工作流程。希望您能相信 Subversion 属性可以增强您的版本控制体验。
属性可以为您的工作副本添加非常有用的功能。实际上,Subversion 本身使用属性来存放特殊信息,以及作为表示需要执行某些特殊处理的一种方式。同样,您也可以将属性用于自己的目的。当然,您可以在属性中执行的操作也可以通过使用常规的版本化文件来完成,但请考虑以下 Subversion 属性使用的示例。
假设您想设计一个网站来存放许多数字照片,并以标题和日期戳的方式显示它们。现在,您的照片集一直在变化,因此您希望尽可能自动化该网站。这些照片可能非常大,因此,与这种类型的网站常见的情况一样,您希望向您的网站访问者提供更小的缩略图。您可以使用传统的来完成此操作。也就是说,您可以将 image123.jpg
和 image123-thumbnail.jpg
并排放置在同一个目录中。或者,如果您想保持文件名相同,您可以在不同的目录中存放缩略图,例如 thumbnails/image123.jpg
。您还可以以类似的方式存储您的标题和日期戳,同样与原始图像文件分开。很快,您的文件树就会变得混乱,并且随着每张新照片添加到网站,文件树会成倍增加。
现在,考虑使用 Subversion 的文件属性的相同设置。想象一下,您有一个图像文件 image123.jpg
,然后在该文件中设置名为 caption
、datestamp
甚至 thumbnail
的属性。现在,您的工作副本目录看起来更加易于管理——实际上,它看起来像是其中只有图像文件。但是您的自动化脚本更了解。它们知道它们可以使用 svn(或者更好的是,它们可以使用 Subversion 语言绑定——参见 名为“使用 C 和 C++ 以外的语言”的部分)来挖掘您的网站显示所需的额外信息,而无需读取索引文件或玩路径操作游戏。
如何(以及是否)使用 Subversion 属性取决于您。正如我们提到的,Subversion 有自己的属性用途,我们将在本章后面介绍。但首先,让我们讨论如何使用 svn 程序来操作属性。
svn 命令提供了几种方法来添加或修改文件和目录属性。对于具有简短、人类可读值的属性,添加新属性最简单的方法可能是指定属性名称和值作为 propset 子命令的命令行参数。
$ svn propset copyright '(c) 2003 Red-Bean Software' calc/button.c property 'copyright' set on 'calc/button.c' $
但我们一直在宣扬 Subversion 为您的属性值提供的灵活性。如果您计划使用多行文本甚至二进制属性值,您可能不希望在命令行上提供该值。因此,propset 子命令接受一个 --file
(-F
) 选项来指定包含新属性值的 文件的名称。
$ svn propset license -F /path/to/LICENSE calc/button.c property 'license' set on 'calc/button.c' $
对您可以用于属性的名称有一些限制。属性名称必须以字母、冒号 (:
) 或下划线 (_
) 开头;之后,您还可以使用数字、连字符 (-
) 和句点 (.
)。[31]
除了 propset 命令外,svn 程序还提供 propedit 命令。此命令使用配置的编辑器程序(参见 名为“配置”的部分)来添加或修改属性。当您运行该命令时,svn 会在包含属性当前值的临时文件(或者如果要添加新属性,则为空文件)上调用您的编辑器程序。然后,您只需在编辑器程序中修改该值,直到它表示您希望存储的属性的新值,保存临时文件,然后退出编辑器程序。如果 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) 2002 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) 2003 Red-Bean Software
甚至还有一个 proplist 命令的变体,它将列出所有属性的名称和值。只需提供 --verbose
(-v
) 选项即可。
$ svn proplist --verbose calc/button.c Properties on 'calc/button.c': copyright : (c) 2003 Red-Bean Software license : ================================================================ Copyright (c) 2003 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 --verbose calc/button.c Properties on 'calc/button.c': copyright : (c) 2003 Red-Bean Software license : $
您需要使用 propdel 命令才能完全删除属性。语法类似于其他属性命令
$ svn propdel license calc/button.c property 'license' deleted from 'calc/button.c'. $ svn proplist --verbose calc/button.c Properties on 'calc/button.c': copyright : (c) 2003 Red-Bean Software $
既然您已经熟悉了所有与属性相关的 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 ___________________________________________________________________ Name: copyright + (c) 2003 Red-Bean Software $
请注意 status 子命令如何在第二列而不是第一列中显示 M
。这是因为我们修改了 calc/button.c
的属性,但没有修改它的文本内容。如果我们两者都更改了,我们也会在第一列中看到 M
(参见 名为“svn status”的部分)。
您可能还注意到 Subversion 目前显示属性差异的非标准方式。您仍然可以运行 svn diff 并将输出重定向以创建可用的补丁文件。 patch 程序会忽略属性补丁,因为按照规则,它会忽略它无法理解的任何噪音。这确实意味着要完全应用由 svn diff 生成的补丁,任何属性修改都需要手动应用。
如您所见,属性修改的存在对典型的 Subversion 工作流没有明显影响。您更新工作副本、检查文件和目录的状态、报告您所做的修改以及将这些修改提交到存储库的一般模式完全不受属性存在与否的影响。 svn 程序有一些额外的子命令用于实际进行属性更改,但这只是唯一明显的差异。
Subversion 对属性没有特定的策略,您可以将它们用于任何目的。Subversion 只要求您不要使用以 svn:
为前缀的属性名称。那是它为自身使用预留的命名空间。事实上,Subversion 定义了某些属性,这些属性对它们附加到的文件和目录具有神奇的效果。在本节中,我们将解开谜团,并描述这些特殊属性如何让您的生活更轻松。
svn:executable
属性用于以半自动方式控制版本化文件的系统级执行权限位。此属性没有定义的值,它的存在表示 Subversion 希望保持执行权限位启用。删除此属性将把执行位的完全控制权恢复到操作系统。
在许多操作系统上,将文件作为命令执行的能力受执行权限位的存在控制。此位通常默认情况下处于禁用状态,并且必须由用户为每个需要它的文件显式启用。在工作副本中,当在更新期间接收到现有文件的新的版本时,新的文件会不断地被创建。这意味着您可能会为一个文件启用执行位,然后更新您的工作副本,如果该文件在更新过程中发生了更改,它的执行位可能会被禁用。因此,Subversion 提供了 svn:executable
属性作为一种方法来保持执行位启用。
此属性对那些没有执行权限位概念的文件系统没有影响,例如 FAT32 和 NTFS。 [33] 此外,尽管它没有定义的值,但 Subversion 在设置此属性时会将其值强制为 *
。最后,此属性仅对文件有效,不适用于目录。
svn:mime-type
属性在 Subversion 中有多种用途。除了作为文件的通用存储位置之外,用于存储文件的多用途互联网邮件扩展 (MIME) 分类,此属性的值还决定了 Subversion 本身的某些行为特征。
例如,如果文件的 svn:mime-type
属性设置为非文本 MIME 类型(通常,任何不以 text/
开头的类型,尽管有一些例外),Subversion 将假定该文件包含二进制数据(即不可读的)。Subversion 通常提供的其中一项好处是,将从服务器在更新期间接收到的更改以上下文、基于行的形式合并到您的工作文件。但是对于被认为包含二进制数据的文件,没有“行”的概念。因此,对于这些文件,Subversion 在更新期间不会尝试执行上下文合并。相反,任何时候您在本地修改了也正在更新的二进制工作副本文件,您的文件将使用 .orig
扩展名重命名,然后 Subversion 会存储一个新的工作副本文件,其中包含在更新期间接收到的更改,但不会包含您自己的本地修改,在原始文件名中。这种行为实际上是为了保护用户免受在无法上下文合并的文件上执行上下文合并的失败尝试。
此外,如果设置了 svn:mime-type
属性,则 Subversion Apache 模块将使用其值来填充 Content-type:
HTTP 标头,以响应 GET 请求。这提供了重要的线索,了解如何在使用 Web 浏览器浏览存储库时显示文件。
svn:ignore
属性包含一个文件模式列表,某些 Subversion 操作将忽略这些模式。它可能是最常用的特殊属性,它与 global-ignores
运行时配置选项(请参阅 名为“Config”的部分)一起使用,以从 svn status、svn add 和 svn import 命令中过滤出未版本化的文件和目录。
svn:ignore
属性背后的原理很容易解释。Subversion 不假设工作副本目录中的每个文件或子目录都打算用于版本控制。资源必须使用 svn add 或 svn import 命令显式地置于 Subversion 的管理之下。因此,工作副本中通常有许多资源未被版本化。
现在,svn status 命令在其输出中显示工作副本中每个未版本化的文件或子目录,这些文件或子目录尚未被 global-ignores
选项(或其内置默认值)过滤掉。这样做是为了让用户可以查看是否忘记将资源添加到版本控制中。
但是 Subversion 不可能猜测应该忽略的每个资源的名称。此外,在特定存储库的 每个 工作副本中,通常会有许多东西应该被忽略。强制该存储库的每个用户将这些资源的模式添加到他们的运行时配置区域不仅是一种负担,而且有可能与用户签出的其他工作副本的配置需求发生冲突。
解决方案是将特定于可能出现在给定目录中的资源的忽略模式与目录本身一起存储。未版本化资源的常见示例,这些资源基本上特定于目录,但很可能出现在那里,包括程序编译的输出。或者,为了使用更适合本书的示例,将一些源 DocBook XML 文件转换为更易读的输出格式后生成的 HTML、PDF 或 PostScript 文件。
为此,svn:ignore
属性是解决方案。它的值是文件模式的多行集合,每行一个模式。该属性设置在您希望应用模式的目录上。 [34] 例如,假设您从 svn status 中获得了以下输出
$ svn status calc M calc/button.c ? calc/calculator ? calc/data.c ? calc/debug_log ? calc/debug_log.1 ? calc/debug_log.2.gz ? calc/debug_log.3.gz
在此示例中,您对 button.c
进行了一些属性修改,但在您的工作副本中,您还有一些未版本化的文件:您从源代码编译的最新 calculator
程序、名为 data.c
的源文件以及一组调试输出日志文件。现在,您知道您的构建系统总是会生成 calculator
程序。 [35] 您还知道您的测试套件总是会留下这些调试日志文件。这些事实对于所有工作副本都是正确的,而不仅仅是您自己的。您也知道您不想在每次运行 svn status 时都看到这些东西。因此,您可以使用 svn propedit svn:ignore calc 将一些忽略模式添加到 calc
目录。例如,您可以在 svn:ignore
属性中添加以下内容作为新值
calculator debug_log*
在您添加此属性后,您现在将在 calc
目录上有一个本地属性修改。但是请注意,您的 svn status 输出中还发生了什么变化
$ svn status M calc M calc/button.c ? calc/data.c
现在,所有无用的东西都从输出中消失了!当然,这些文件仍然存在于您的工作副本中。Subversion 只是没有提醒您它们存在并且未版本化。现在,所有琐碎的噪音都从显示中消失了,您只剩下更有意义的项目,例如您可能忘记添加到版本控制中的源代码文件。
如果您想查看被忽略的文件,您可以将 --no-ignore
选项传递给 Subversion
$ svn status --no-ignore M calc/button.c I calc/calculator ? calc/data.c I calc/debug_log I calc/debug_log.1 I calc/debug_log.2.gz I calc/debug_log.3.gz
忽略模式列表还被 svn add 和 svn import 使用。这两个操作都涉及请求 Subversion 开始管理一组文件和目录。Subversion 不会强迫用户选择要开始版本化的树中的哪些文件,而是使用忽略模式来确定哪些文件不应该作为更大的递归添加或导入操作的一部分被扫入版本控制系统。
Subversion 能够将 关键字(关于版本化文件的有用、动态信息的片段)替换到文件本身的内容中。关键字通常描述关于文件上次已知修改时间的信息。因为此信息在每次文件更改时都会改变,更重要的是,在文件更改之后才会改变,所以,除了版本控制系统之外,任何进程都很难让数据保持完全最新。如果留给人类作者,这些信息不可避免地会变得陈旧。
例如,假设您有一份文档,您想在其中显示上次修改的日期。您可以让该文档的每位作者在提交更改之前,也调整描述上次更改时间的部分。但迟早会有人忘记这样做。相反,只需让 Subversion 对 LastChangedDate
关键字执行关键字替换。您可以通过在文件中的所需位置放置一个 关键字锚点 来控制关键字插入的位置。这个锚点只是一个格式为 $
KeywordName
$
的文本字符串。
所有关键字在作为文件中的锚点出现时都区分大小写:您必须使用正确的字母大小写才能展开关键字。您还应将svn:keywords
属性的值视为区分大小写的——某些关键字名称将被识别,无论大小写如何,但这种行为已弃用。
Subversion 定义了可用于替换的关键字列表。该列表包含以下五个关键字,其中一些具有您也可以使用的别名
日期
此关键字描述了文件在存储库中最后一次已知更改的时间,类似于$Date: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $
。它也可以指定为LastChangedDate
。
版本
此关键字描述了此文件在存储库中最后一次已知更改的版本,类似于$Revision: 144 $
。它也可以指定为LastChangedRevision
或Rev
。
作者
此关键字描述了最后一次已知更改此文件的用户,类似于$Author: harry $
。它也可以指定为LastChangedBy
。
HeadURL
此关键字描述了存储库中文件最新版本的完整 URL,类似于$HeadURL: http://svn.collab.net/repos/trunk/README $
。它可以缩写为URL
。
Id
此关键字是其他关键字的压缩组合。它的替换类似于$Id: calc.c 148 2002-07-28 21:30:43Z sally $
,表示文件calc.c
最后一次更改是在 2002 年 7 月 28 日晚上,由用户sally
在版本 148 中进行的。
仅仅将关键字锚文本添加到您的文件中不会有任何特殊效果。除非明确要求,否则 Subversion 永远不会尝试对您的文件内容进行文本替换。毕竟,您可能正在编写一篇关于如何使用关键字的文档[36],并且您不希望 Subversion 替换您漂亮的未替换关键字锚示例!
要告诉 Subversion 是否在特定文件上替换关键字,我们再次转向与属性相关的子命令。svn:keywords
属性在设置在版本控制的文件上时,控制将在该文件上替换哪些关键字。该值是前表中找到的关键字名称或别名的空格分隔列表。
例如,假设您有一个名为weather.txt
的版本控制文件,看起来像这样
Here is the latest report from the front lines. $LastChangedDate$ $Rev$ Cumulus clouds are appearing more frequently as summer approaches.
在该文件上没有设置svn:keywords
属性的情况下,Subversion 不会执行任何特殊操作。现在,让我们启用对LastChangedDate
关键字的替换。
$ svn propset svn:keywords "Date Author" weather.txt property 'svn:keywords' set on 'weather.txt' $
现在您已在weather.txt
文件上进行了本地属性修改。您不会看到文件内容的任何更改(除非您在设置属性之前进行了一些自己的更改)。请注意,该文件包含Rev
关键字的关键字锚,但我们没有将该关键字包含在我们设置的属性值中。Subversion 将很乐意忽略对文件中不存在的关键字的替换请求,并且不会替换svn:keywords
属性值中不存在的关键字。
在您提交此属性更改后,Subversion 将使用新的替换文本更新您的工作文件。您将看不到您的关键字锚$LastChangedDate$
,而是看到其替换结果。该结果还包含关键字的名称,并且继续用美元符号 ($
) 字符包围。正如我们预测的那样,Rev
关键字没有被替换,因为我们没有要求它被替换。
另请注意,我们已将svn:keywords
属性设置为“Date Author”,但使用的关键字锚是别名$LastChangedDate$
,并且仍然正确扩展。
Here is the latest report from the front lines. $LastChangedDate: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $ $Rev$ Cumulus clouds are appearing more frequently as summer approaches.
如果其他人现在对weather.txt
进行了更改,您的文件副本将继续显示与之前相同的替换关键字值,直到您更新工作副本。那时,您weather.txt
文件中的关键字将使用反映对该文件最新已知提交的信息重新替换。
Subversion 1.2 引入了关键字语法的变体,它带来了额外的、有用的(虽然可能不典型)功能。您现在可以告诉 Subversion 保持替换关键字的固定长度(就所占字节数而言)。通过在关键字名称后面使用双冒号 (::
),然后是一定数量的空格,您可以定义该固定宽度。当 Subversion 准备将您的关键字替换为关键字及其值时,它基本上只替换这些空格,从而保持关键字字段的总体宽度不变。如果替换的值短于定义的字段宽度,则替换字段的末尾将有额外的填充字符(空格);如果它太长,它将被截断,并在最终的美元符号终止符之前使用特殊的哈希 (#
) 字符。
例如,假设您有一个文档,其中您有一些表格数据部分反映了文档的 Subversion 关键字。使用原始的 Subversion 关键字替换语法,您的文件可能看起来像这样
$Rev$: Revision of last commit $Author$: Author of last commit $Date$: Date of last commit
现在,这在开始时看起来很漂亮且表格化。但是当您提交该文件时(当然,启用关键字替换),您会看到
$Rev: 12 $: Revision of last commit $Author: harry $: Author of last commit $Date: 2006-03-15 02:33:03 -0500 (Wed, 15 Mar 2006) $: Date of last commit
结果不是那么美观。您可能很想在替换后调整文件,使其再次看起来像表格。但这只在关键字值具有相同宽度的情况下有效。如果最后提交的版本进入了一个新的位置值(例如,从 99 到 100),或者如果另一个用户名更长的用户提交了该文件,事情就会再次变得混乱。但是,如果您使用的是 Subversion 1.2 或更高版本,则可以使用新的固定长度关键字语法,定义一些看起来合理的字段宽度,现在您的文件可能看起来像这样
$Rev:: $: Revision of last commit $Author:: $: Author of last commit $Date:: $: Date of last commit
您将此更改提交到您的文件。这次,Subversion 注意到新的固定长度关键字语法,并保持您在双冒号和尾随美元符号之间放置的填充所定义的字段宽度。替换后,字段的宽度完全不变——Rev
和Author
的短值用空格填充,而长的Date
字段则被哈希字符截断
$Rev:: 13 $: Revision of last commit $Author:: harry $: Author of last commit $Date:: 2006-03-15 0#$: Date of last commit
当将替换执行到复杂的、自身使用固定长度字段存储数据的文件格式中时,或当给定数据字段的存储大小难以从格式的本机应用程序之外进行修改时(例如,对于 Microsoft Office 文档),使用固定长度关键字尤其方便。
请注意,由于关键字字段的宽度以字节为单位,因此存在破坏多字节值的可能性。例如,包含一些多字节 UTF-8 字符的用户名可能会在组成其中一个字符的字节字符串中间被截断。结果将是在字节级别进行的简单截断,但在作为 UTF-8 文本查看时,它可能看起来像字符串的最后一个字符不正确或混乱。可以想象,某些应用程序在被要求加载文件时,会注意到损坏的 UTF-8 文本并认为整个文件已损坏,从而拒绝完全操作该文件。
除非使用版本控制文件的svn:mime-type
属性另行说明,否则 Subversion 假设该文件包含人类可读的数据。一般来说,Subversion 仅使用此知识来确定该文件的上下文差异报告是否可能。否则,对于 Subversion 来说,字节就是字节。
这意味着默认情况下,Subversion 不会关注您的文件中使用的行尾 (EOL) 标记类型。不幸的是,不同的操作系统使用不同的标记来表示文件中的文本行尾。例如,Windows 平台上的软件通常使用的行尾标记是一对 ASCII 控制字符——回车 (CR
) 和换行 (LF
)。但是,Unix 软件仅使用LF
字符来表示行尾。
并非所有这些操作系统上的各种工具都准备好在格式与运行它们的系统的本机行尾样式不同的文件中包含行尾的文件。常见的结果是 Unix 程序将 Windows 文件中存在的CR
字符视为普通字符(通常呈现为^M
),而 Windows 程序将 Unix 文件的所有行组合成一个巨大的行,因为没有找到回车换行 (或CRLF
) 字符组合来表示行尾。
这种对外国 EOL 标记的敏感性对于在不同操作系统之间共享文件的用户来说可能会令人沮丧。例如,考虑一个源代码文件,以及在 Windows 和 Unix 系统上编辑此文件的开发人员。如果所有开发人员始终使用保留文件行尾样式的工具,则不会出现问题。
但在实践中,许多常见的工具要么无法正确读取包含外国 EOL 标记的文件,要么在保存文件时将文件的行尾转换为本机样式。如果是前者,开发人员必须使用外部转换实用程序(例如dos2unix或其配套程序unix2dos)来准备文件进行编辑。后者不需要额外的准备。但这两种情况都会导致与原始文件不同的文件,实际上每行都不同!在提交更改之前,用户有两个选择。他可以使用转换实用程序将修改后的文件恢复到在他进行编辑之前所处的相同行尾样式。或者,他只需提交文件——新的 EOL 标记和所有内容。
这些情况的结果包括浪费时间和对提交文件的无用修改。浪费时间已经很痛苦。但是当提交更改了文件中的每一行时,这会使确定哪些行以非平凡的方式更改变得复杂。该错误到底在哪里修复的?在哪个行引入了语法错误?
解决此问题的办法是svn:eol-style
属性。当此属性设置为有效值时,Subversion 将使用它来确定对文件执行哪些特殊处理,以便文件的行尾样式不会随着来自不同操作系统的每次提交而不断变化。有效值为
native
这会导致文件包含 Subversion 运行所在的系统中本地的 EOL 标记。换句话说,如果 Windows 上的用户检出一个包含 svn:eol-style
属性设置为 native
的文件的版本库,那么该文件将包含 CRLF
EOL 标记。Unix 用户检出一个包含相同文件的版本库,将在他的文件副本中看到 LF
EOL 标记。
请注意,无论操作系统如何,Subversion 实际上都会使用标准化的 LF
EOL 标记将文件存储在版本库中。这对用户来说基本上是透明的。
CRLF
这会导致文件包含 CRLF
序列作为 EOL 标记,无论使用的是什么操作系统。
LF
这会导致文件包含 LF
字符作为 EOL 标记,无论使用的是什么操作系统。
CR
这会导致文件包含 CR
字符作为 EOL 标记,无论使用的是什么操作系统。这种行尾样式并不常见。它在旧的 Macintosh 平台上使用(Subversion 甚至不能在这些平台上运行)。
svn:externals
属性包含 Subversion 用于使用一个或多个其他检出的 Subversion 工作副本填充版本控制目录的指令。有关此关键字及其用法的更多信息,请参阅 名为“Externals Definitions”的部分。
svn:special
属性是唯一一个不希望用户直接设置或修改的 svn:
属性。当“特殊”对象(例如符号链接)被安排添加时,Subversion 会自动设置此属性。版本库将 svn:special
对象存储为普通文件。但是,当客户端在签出或更新期间看到此属性时,它会解释文件的内容并将项目转换回特殊类型的对象。在撰写本文时的 Subversion 版本中,只有版本化的符号链接具有此属性附加,但在未来的 Subversion 版本中,其他特殊类型的节点可能会使用此属性。
注意:Windows 客户端没有符号链接,因此会忽略来自声称是符号链接的版本库的任何 svn:special
文件。在 Windows 上,用户最终会在工作副本中获得一个普通的版本控制文件。
此属性用于表示其附加到的文件应该在编辑之前被锁定。该属性的值无关紧要;Subversion 会将其值标准化为 *
。当存在时,文件将是只读的,除非用户显式地锁定了该文件。当存在锁令牌(作为运行 svn lock 的结果)时,文件将变为读写。当锁被释放时,文件将再次变为只读。
要了解有关如何、何时以及为何应该使用此属性的更多信息,请参阅 名为“Lock Communication”的部分。
属性是 Subversion 的一个强大功能,是本章和其他章节中讨论的许多 Subversion 功能的关键组成部分——文本差异和合并支持、关键字替换、换行符转换等。但是,为了充分利用属性,必须在正确的文件和目录上设置它们。不幸的是,这可能是日常工作中很容易被忘记的一步,尤其是因为没有设置属性通常不会导致明显的错误条件(至少与,比如,没有将文件添加到版本控制相比)。为了帮助您将属性应用到需要它们的地方,Subversion 提供了几个简单但有用的功能。
每当您使用 svn add 或 svn import 命令将文件引入版本控制时,Subversion 会运行一个非常基本的启发式方法来确定该文件是否包含人类可读或非人类可读的内容。如果做出后者决定,Subversion 会自动将 svn:mime-type
属性设置为该文件,将其设置为 application/octet-stream
(通用“这是一个字节集合”MIME 类型)。当然,如果 Subversion 猜测错误,或者您希望将 svn:mime-type
属性设置为更精确的内容——也许是 image/png
或 application/x-shockwave-flash
——您始终可以删除或编辑该属性。
Subversion 还提供了自动属性功能,允许您创建文件名模式到属性名称和值的映射。这些映射是在您的运行时配置区域中完成的。它们也会影响添加和导入,不仅可以覆盖 Subversion 在这些操作期间做出的任何默认 MIME 类型决定,还可以设置额外的 Subversion 或自定义属性。例如,您可以创建一个映射,说明每当您添加 JPEG 文件时——与模式 *.jpg
匹配的文件——Subversion 应该自动将这些文件的 svn:mime-type
属性设置为 image/jpeg
。或者,也许任何与 *.cpp
匹配的文件都应该将其 svn:eol-style
设置为 native
,并将 svn:keywords
设置为 Id
。自动属性支持也许是 Subversion 工具箱中最方便的属性相关工具。有关配置该支持的更多信息,请参阅 名为“Config”的部分。