本文档正在进行中,内容可能会发生很大变化,并且可能无法准确描述 Apache™ Subversion® 软件的任何已发布版本。 将此页面添加为书签或以其他方式向他人推荐此页面可能不是一个明智的做法。 请访问 https://svnbook.subversion.org.cn/ 以获取本文档的稳定版本。

忽略未版本控制的项目

在任何给定的工作副本中,很有可能在所有已版本控制的文件和目录旁边,还存在其他既未版本控制也未打算版本控制的文件和目录。 文本编辑器会将备份文件散布在目录中。 软件编译器会生成中间文件,甚至最终文件,这些文件通常不会版本控制。 用户自己也会在他们认为合适的地方随意放置各种其他文件和目录,通常放在版本控制工作副本中。

期望 Subversion 工作副本对这种混乱和不纯洁保持不受影响是荒谬的。 事实上,Subversion 将其工作副本仅仅是典型目录,就像未版本控制的树一样,视为一项 特性。 但是,这些不应版本控制的文件和目录可能会给 Subversion 用户带来一些困扰。 例如,由于 svn addsvn import 命令默认情况下会递归地执行,并且不知道您希望对给定树中的哪些文件进行版本控制,因此很容易意外地将您不打算版本控制的内容添加到版本控制中。 并且由于 svn status 默认情况下会报告工作副本中所有感兴趣的项目,包括未版本控制的文件和目录,因此在存在许多此类项目的地方,其输出可能会变得非常嘈杂。

因此,Subversion 提供了几种方法来告诉它哪些文件它可以忽略。 其中一种方法涉及使用 Subversion 的运行时配置系统(请参阅 名为“运行时配置区域”的部分),因此适用于使用该运行时配置的所有 Subversion 操作,通常是在特定计算机上或由特定计算机用户执行的操作。 另外两种方法利用了 Subversion 的目录属性支持,并且与版本控制树本身联系更紧密,因此影响了拥有该树工作副本的每个人。 所有这些机制都使用 文件模式(用于匹配文件名的文字和特殊通配符字符的字符串)来决定哪些文件应该忽略。

Subversion 运行时配置系统提供了一个选项 global-ignores,其值是一个由空格分隔的文件模式集合。 Subversion 客户端会将这些模式与将要添加到版本控制中的文件的名称进行比较,以及与 svn status 命令注意到的未版本控制的文件进行比较。 如果任何文件的名称与其中一个模式匹配,Subversion 将基本上一视同仁,就像该文件根本不存在一样。 这对于您几乎从不希望版本控制的各种文件非常有用,例如编辑器备份文件,例如 Emacs 的 *~.*~ 文件。

在版本控制目录中找到时,svn:ignore 属性应包含一个换行符分隔的文件模式列表,Subversion 应使用这些模式来确定 相同 目录中可忽略的对象。 这些模式不会覆盖 global-ignores 运行时配置选项中找到的模式,而是附加到该列表。 值得再次注意的是,与 global-ignores 选项不同,在 svn:ignore 属性中找到的模式仅适用于设置该属性的目录,而不适用于其任何子目录。 svn:ignore 属性是告诉 Subversion 忽略在该目录的每个用户的每个工作副本中都可能存在的文件的好方法,例如编译器输出,或者更适合本文档的一个示例,即由将一些源 DocBook XML 文件转换为更易读的输出格式而生成的 HTML、PDF 或 PostScript 文件。

Subversion 1.8 提供了 svn:ignore 属性的更强大的版本,即 svn:global-ignores 属性。 与 svn:ignore 属性一样,svn:global-ignores 只能设置在目录上,并且包含 Subversion 用于确定可忽略对象的文件模式。 [21] 这些忽略模式也会附加到在 global-ignores 运行时配置选项中定义的任何模式,以及定义的任何 svn:ignore 模式。 但是,与 svn:ignore 不同,svn:global-ignores 属性是可继承的 [22],并且适用于设置该属性的目录下的 所有 路径,而不仅仅是目录的直接子级。

[Note] 注意

Subversion 对可忽略文件模式的支持仅扩展到将未版本控制的文件和目录添加到版本控制的一次性过程。 对象一旦处于 Subversion 的控制之下,忽略模式机制便不再对其适用。 换句话说,不要期望 Subversion 仅因为文件的名称与忽略模式匹配而避免提交对版本控制文件的更改,Subversion 始终 会注意到它版本控制的所有对象。

global-ignores 运行时配置选项中的忽略模式往往更多是个人喜好问题 [23],并且与用户的特定工具链联系更紧密,而不是与特定工作副本需求的细节联系更紧密。 因此,本节的其余部分将重点介绍 svn:ignoresvn:global-ignores 属性及其用途。

假设您从 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 程序。 [24] 并且您知道您的测试套件始终会留下这些调试日志文件。 这些事实适用于此项目的每个工作副本,而不仅仅是您自己的工作副本。 并且您知道您不想在每次运行 svn status 时都看到这些内容,并且您非常确定其他人也不想看到这些内容。 因此,您可以使用 svn propedit svn:ignore calc 将一些忽略模式添加到 calc 目录中。

$ svn propget svn:ignore calc
calculator
debug_log*
$

添加此属性后,您现在将在 calc 目录上有一个本地属性修改。 但请注意,您的 svn status 输出还有哪些不同之处

$ svn status
 M      calc
 M      calc/button.c
?       calc/data.c

现在,所有这些杂乱信息都从输出中消失了! 您的 calculator 编译程序以及所有这些日志文件仍然存在于您的工作副本中;Subversion 只是没有不断地提醒您它们存在并且未版本控制。 现在,所有不令人感兴趣的噪声都从显示中删除了,只剩下更引人入胜的项目,例如您可能忘记添加到版本控制中的源代码文件 data.c

当然,这并不是您工作副本状态的唯一报告方式。 如果您确实希望在状态报告中看到忽略的文件,则可以将 --no-ignore 选项传递给 Subversion

$ svn status --no-ignore
 M      calc
 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
I       calc/wip.1.diff

您之前隐藏的所有未版本控制的路径再次显示,但现在显示为 'I' Ignored 状态。 但是等等,wip.1.diff 怎么样? calc 上的 svn:ignore 属性不包含任何与该文件名匹配的模式,那么为什么它会被忽略呢? [25] 答案在于 Subversion 可以忽略未版本控制路径的第三种方法,即可继承的 svn:global-ignores 属性。 使用 --show-inherited-props 选项与 svn propget 子命令,您会看到 svn:global-ignores 属性已设置为工作副本的根目录,并且可以肯定的是,它定义了一个匹配的忽略模式

$ svn pg svn:global-ignores calc -v --show-inherited-props
Inherited properties on 'calc',
from '.':
  svn:global-ignores
    *.diff
    *.patch

如前所述,忽略的文件模式列表也由 svn addsvn import 使用。 这两种操作都涉及要求 Subversion 开始管理一组文件和目录。 Subversion 不会强迫用户选择要开始版本控制的树中的哪些文件,而是使用忽略模式(全局模式、每个目录模式和继承的列表)来确定哪些文件不应作为大型递归添加或导入操作的一部分被纳入版本控制系统。 在这里,您也可以使用 --no-ignore 选项告诉 Subversion 忽略其忽略列表,并对存在的所有文件和目录进行操作。

[Tip] 提示

即使设置了 svn:ignoresvn:global-ignores,如果在命令中使用 shell 通配符,你可能会遇到问题。Shell 通配符在 Subversion 对它们进行操作之前被扩展成一个明确的目标列表,所以运行 svn SUBCOMMAND * 等同于运行 svn SUBCOMMAND file1 file2 file3 …。在 svn add 命令的情况下,这类似于传递 --no-ignore 选项的效果。因此,不要使用通配符,而应该使用 svn add --force . 来批量安排未版本化的内容以进行添加。明确的目标将确保当前目录不会因已处于版本控制下而被忽略,而 --force 选项将导致 Subversion 遍历该目录,添加未版本化的文件,同时仍然遵守 svn:ignoresvn:global-ignores 属性以及 global-ignores 运行时配置变量。如果不想对要添加的内容进行完全递归遍历,请务必在 svn add 命令中提供 --depth files 选项。



[21] svn:global-ignores 属性中的忽略模式可以用任何空白字符分隔(类似于 global-ignores 运行时配置选项),而不仅仅是换行符(与 svn:ignore 属性一样)。

[22] 当然,只有 1.8 或更高版本的 Subversion 客户端才能识别 svn:global-ignores 属性的可继承性和特殊含义!

[23] 虽然只是个人喜好,但如果未明确设置 global-ignores 运行时配置选项(无论将其设置为首选模式集还是空字符串),Subversion 都会使用默认值。请参见 名为“General configuration”的部分 中的 global-ignores 条目。

[24] 这难道不是构建系统的全部目的吗?

[25] 假设你的 global-ignores 运行时配置中没有任何匹配的模式。

TortoiseSVN 官方中文版 1.14.7 发布