本文档旨在描述 Apache™ Subversion® 的 1.7.x 系列。如果您运行的是其他版本的 Subversion,强烈建议您访问 https://svnbook.subversion.org.cn/ 并查阅适合您 Subversion 版本的文档。

锚定修订和操作修订

我们经常在计算机上复制、移动、重命名和完全替换文件和目录。您的版本控制系统也不应该妨碍您对版本控制的文件和目录执行这些操作。Subversion 的文件管理支持非常灵活,为版本控制的文件提供了几乎与操作未版本控制的文件一样多的灵活性。但是,这种灵活性意味着在存储库的生命周期中,给定的版本控制对象可能具有许多路径,而给定的路径可能代表几个完全不同的版本控制对象。这给您与这些路径和对象的交互带来了某种程度的复杂性。

Subversion 非常聪明,能够注意到当对象的版本历史包含这样的 地址变更 时。例如,如果您请求上周重命名的特定文件的修订历史记录日志,Subversion 会很乐意提供所有这些日志——重命名本身发生的修订,以及重命名之前和之后相关修订的日志。因此,大多数情况下,您甚至不必考虑这些事情。但偶尔,Subversion 需要您的帮助来消除歧义。

最简单的例子是,当一个目录或文件从版本控制中删除,然后一个新的目录或文件使用相同的名称创建并添加到版本控制中。您删除的东西和您后来添加的东西不是同一个东西。它们只是碰巧具有相同的路径——例如,/trunk/object。那么,询问 Subversion 关于 /trunk/object 的历史意味着什么?您是在询问当前位于该位置的东西,还是您从该位置删除的旧东西?您是在询问对曾经位于该路径的 所有 对象执行的操作吗?Subversion 需要一个提示,了解您真正想要什么。

由于移动操作,版本控制对象的版本历史甚至可能比这更复杂。例如,您可能有一个名为 concept 的目录,其中包含您一直在玩弄的某个新兴软件项目。但是,最终,该项目成熟到足以让这个想法真正有了一些翅膀,因此您做出了不可想象的事情,决定给该项目起一个名字。 [11] 假设您将软件命名为 Frabnaggilywort。此时,将目录重命名以反映项目的新的名称是有意义的,因此 concept 重命名为 frabnaggilywort。生活继续,Frabnaggilywort 发布了 1.0 版本,并被成群结队希望改善生活的人们每天下载和使用。

这真是一个美好的故事,但故事并没有到此结束。您是一位企业家,您已经有了另一个想法。因此,您创建了一个新的目录,concept,循环再次开始。事实上,循环在多年内多次开始,每次都从那个旧的 concept 目录开始,然后有时看到该目录在想法成熟时被重命名,有时看到它在您放弃想法时被删除。或者,为了变得更加复杂,您可能将 concept 重命名为其他名称一段时间,但后来出于某种原因又将该名称改回 concept

在这样的场景中,尝试指示 Subversion 使用这些重复路径就像指示芝加哥西郊的司机沿着罗斯福路向东行驶,然后左转到梅恩街一样。仅仅 20 分钟,你就可以穿过惠顿、格伦艾林和隆巴德的 梅恩街。而且,它们并不是同一条街。我们的司机——以及我们的 Subversion——需要更多细节才能做正确的事情。

幸运的是,Subversion 允许你告诉它你指的是哪条梅恩街。使用的机制称为 锚定修订版,你将其提供给 Subversion 的唯一目的是标识唯一的历史线。因为在任何给定时间(或更准确地说,在任何一个修订版中),最多只有一个版本化的对象可以占据一个路径,所以路径和锚定修订版的组合足以明确地标识一条特定的历史线。锚定修订版使用 at 语法指定给 Subversion 命令行客户端,之所以这样称呼是因为语法涉及将一个 at 符号 (@) 和锚定修订版附加到与该修订版关联的路径的末尾。

但是,我们在这本书中反复提到的 --revision (-r) 怎么办?该修订版(或修订版集)称为 操作修订版(或 操作修订版范围)。一旦使用路径和锚定修订版标识了特定的历史线,Subversion 就会使用操作修订版执行请求的操作。为了将这映射到我们芝加哥地区的街道类比,如果我们被告知去惠顿的 606 N. 梅恩街,[12] 我们可以将 梅恩街 视为我们的路径,将 惠顿 视为我们的锚定修订版。这两部分信息标识了可以行驶的唯一路径(梅恩街的南北方向),并且它们阻止我们在错误的梅恩街上上下行驶以寻找目的地。现在,我们将 606 N. 作为我们的操作修订版,我们就知道 确切 的目的地。

假设很久以前我们创建了我们的存储库,在版本 1 中,我们添加了第一个 concept 目录,以及该目录中关于该概念的 IDEA 文件。 在添加和调整实际代码的几个版本之后,我们在版本 20 中将此目录重命名为 frabnaggilywort。 到版本 27,我们有了新的概念,一个新的 concept 目录来保存它,以及一个新的 IDEA 文件来描述它。 然后五年过去了,数千个版本过去了,就像它们在任何好的爱情故事中一样。

现在,几年后,我们想知道 IDEA 文件在版本 1 中是什么样子的。 但是 Subversion 需要知道我们是在询问 当前 文件在版本 1 中的样子,还是在询问版本 1 中 concept/IDEA 位置的文件的内容。 当然,这些问题有不同的答案,由于 peg 版本,您可以提出这些问题。 要找出当前 IDEA 文件在那个旧版本中的样子,您可以运行

$ svn cat -r 1 concept/IDEA 
svn: E195012: Unable to find repository location for 'concept/IDEA' in revision 1

当然,在这个例子中,当前的 IDEA 文件在版本 1 中还不存在,所以 Subversion 会报错。 上面的命令是更长表示法的简写,它明确列出了 peg 版本。 展开的表示法是

$ svn cat -r 1 concept/IDEA@BASE
svn: E195012: Unable to find repository location for 'concept/IDEA' in revision 1

执行后,它具有预期的结果。

细心的读者可能此时会想知道,peg 修订语法是否会对工作副本路径或 URL 中实际包含“@”符号的情况造成问题。毕竟,svn 如何知道 news@11 是我树中目录的名称,还是仅仅是 news 的修订版本 11 的语法?值得庆幸的是,虽然 svn 始终会假设后者,但有一个简单的解决方法。您只需在路径末尾追加一个“@”符号,例如 news@11@svn 只关心参数中的最后一个“@”符号,并且在该“@”符号之后省略字面 peg 修订说明符并不被认为是非法的。此解决方法甚至适用于以“@”符号结尾的路径——您可以使用 filename@@ 来讨论名为 filename@ 的文件。

那么,让我们问另一个问题——在修订版本 1 中,位于地址 concepts/IDEA 的文件的原始内容是什么?我们将使用显式 peg 修订来帮助我们。

$ svn cat concept/IDEA@1
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

请注意,我们这次没有提供操作修订。这是因为当没有指定操作修订时,Subversion 会假设一个默认的操作修订,该修订与 peg 修订相同。

如您所见,我们操作的输出似乎是正确的。文本甚至提到了 frabbing naggily worts,因此这几乎可以肯定就是描述现在称为 Frabnaggilywort 的软件的文件。实际上,我们可以使用显式 peg 修订和显式操作修订的组合来验证这一点。我们知道,在 HEAD 中,Frabnaggilywort 项目位于 frabnaggilywort 目录中。因此,我们指定要查看在 HEAD 中标识为路径 frabnaggilywort/IDEA 的历史记录行在修订版本 1 中的样子。

$ svn cat -r 1 frabnaggilywort/IDEA@HEAD
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

peg 和操作修订也不必如此简单。例如,假设 frabnaggilywort 已从 HEAD 中删除,但我们知道它存在于修订版本 20 中,并且我们想查看其 IDEA 文件在修订版本 4 和 10 之间的差异。我们可以使用 peg 修订版本 20 以及在修订版本 20 中保存 Frabnaggilywort 的 IDEA 文件的 URL,然后使用 4 和 10 作为我们的操作修订范围。

$ svn diff -r 4:10 http://svn.red-bean.com/projects/frabnaggilywort/IDEA@20
Index: frabnaggilywort/IDEA
===================================================================
--- frabnaggilywort/IDEA	(revision 4)
+++ frabnaggilywort/IDEA	(revision 10)
@@ -1,5 +1,5 @@
-The idea behind this project is to come up with a piece of software
-that can frab a naggily wort.  Frabbing naggily worts is tricky
-business, and doing it incorrectly can have serious ramifications, so
-we need to employ over-the-top input validation and data verification
-mechanisms.
+The idea behind this project is to come up with a piece of
+client-server software that can remotely frab a naggily wort.
+Frabbing naggily worts is tricky business, and doing it incorrectly
+can have serious ramifications, so we need to employ over-the-top
+input validation and data verification mechanisms.

幸运的是,大多数人不会遇到如此复杂的情况。但当你遇到时,请记住,挂钩修订是 Subversion 需要消除歧义的额外提示。



[11] 你不应该给它起名字。一旦你给它起名字,你就会开始对它产生感情。—Mike Wazowski

[12] 伊利诺伊州惠顿市北梅恩街 606 号是惠顿 历史中心的所在地。这似乎很合适…….

TortoiseSVN 官方中文版 1.14.7 发布