9.Peg和实施修订版本

Posted on Posted in 4.高级主题

Peg和实施修订版本

文件和目录的拷贝、改名和移动能力使你可以创建一个项目,然后删除它,然后在同一个位置添加一个新的—这是在我们的计算机中经常发生的操作,而你的版本控制系统不应该成为你这样操作的障碍。Subversion的文件管理操作是这样的开放,提供了几乎和普通文件一样的操作版本化文件的灵活性,但是灵活意味着在整个版本库的生命周期中,一个给定的版本化的资源可能会出现在许多不同的路径,一个给定的路径会展示给我们许多完全不同的版本化资源。当然这些功能也增加了你与这些路径和资源交互的难度。

Subversion可以非常聪明的注意到一个对象的包括一个“地址改变”历史变化,举个例子,如果你询问一个曾经上周改过名的文件的所有的日志信息,Subversion会很高兴提供所有的日志—重命名发生的修订版本,外加相关版本之前和之后的修订版本日志,所以大多数时间里,你不需要考虑这些事情,但是偶尔,Subversion会需要你的帮助来清除混淆。

这个最简单的例子发生在当一个目录或者文件从版本控制中删除时,然后一个新的同样名字目录或者文件添加到版本控制,显然你删除的和你后来添加的不是同样的东西,它们仅仅是有同样的路径,例如/trunk/object。什么,这意味着询问Subversion来查看/trunk/object的历史?你是询问当前这个位置的东西还是你在这个位置删除的那个对象?你是希望询问对这个对象的所有操作还是这个路径的所有对象?很明显,Subversion需要线索知道你真实的想法。

由于移动,版本化对象的历史会变得非常扭曲。举个例子,你会有一个目录叫做concept,保存了一些你用来试验的初生的软件项目,最终,这个项目变得足够成熟,说明这个注意确实需要一些翅膀了,所以你决定给这个项目一个名字。 [18]假定你叫你的软件为Frabnaggilywort,此刻,把你的目录命名为反映项目名称的名字是有意义的,所以concept改名为frabnaggilywort。生活还在继续,Frabnaggilywort发布了1.0版本,并且被许多希望改进他们生活的分散用户天天使用。

这是一个美好的故事,但是没有在这里结束,作为主办人,你一定想到了另一件事,所以你创建了一个目录叫做concept,周期重新开始。实际上,这个循环在几年里开始了多次,每一个想法从使用旧的concept目录开始,然后有时在想法成熟之后重新命名,有时你放弃了这个注意而删除了这个目录。或者更加变态一点,或许你把concept改成其他名字之后又因为一些原因重新改回concept

当这样的情景发生时,指导Subversion工作在重新使用的路径上的尝试就像指导一个芝加哥西郊的乘客驾车到东面的罗斯福路并且左转到主大道。仅仅20分钟,你可以穿过惠顿、格伦埃林何朗伯德的“主大道”,但是它们不是一样的街道,我们的乘客—和我们的Subversion—需要更多的细节来做正确的事情。

在1.1版本,Subversion提供了一种方法来说明你所指是哪一个街道,叫做peg修订版本,通过这个修订版本我们可以唯一确定一条历史线路,因为一个版本化的文件会在任何时间占用某个路径—路径和peg修订版本的合并是可以指定一个历史的特定线路。Peg修订版本可以在Subversion命令行客户端中用at语法指定,之所以使用这个名称是因为会在关联的修订版本的路径后面追加一个“at符号”(@)。

但是我们在本书多次提到的--revision (-r)到底是什么?修订版本(或者是修订版本集)叫做实施的修订版本(或者叫做实施的修订版本范围),一旦一个特定历史线路通过一个路径和peg修订版本指定,Subversion会使用实施的修订版本执行要求的操作。类似的,为了指出这个到我们芝加哥的道路,如果我们被告知到惠顿主大道606号, [19] 我们可以把“主大道”看作路径,把“惠顿”当作我们的peg修订版本。这两段信息确认了我们可以旅行(主大道的北方或南方)的唯一路径,也会保持我们不会在前前后后寻找目标时走到错误的主大道。现在我们把“606 N.”作为我们实施的修订版本,我们精确的知道到哪里。

Peg 版本算法

Subversion命令行在解决路径和修订版本混淆时需要peg修订版本算法,这里是一个用以说明的例子:

$ svn command -r OPERATIVE-REV item@PEG-REV

       

如果OPERATIVE-REVPEG-REV更老,则算法如下:

  • 来到修订版本PEG-REV,找到item,在版本库定位到一个唯一的对象。

  • 追踪对象的历史背景(通过任何可能的改名)来到修订版本OPERATIVE-REV的祖先。

  • 对那个祖先执行请求的动作,无论它的位置,无论它是什么名字,无论当时是否存在。

但是如果OPERATIVE-REVPEG-REV更年轻时会怎么样?这为定位OPERATIVE-REV中的路径的理论问题增加了一些复杂性,因为在PEG-REVOPERATIVE-REV之间,路径在历史中可以出现多次(由于拷贝操作),而且那还不是全部—Subversion不会保存向前跟踪历史的足够信息,所以算法会有一点不同:

  • 来到修订版本PEG-REV,找到item,在版本库定位到一个唯一的对象。

  • 追踪对象的历史背景(通过任何可能的改名)来到修订版本PEG-REV的祖先。

  • PEG-REV中检验对象的位置(顺序)与在OPERATIVE-REV中相同,如果那是问题,则至少两个位置是直接关联的,所以在OPERATIVE-REV的位置执行请求动作。否则,关联没有建立,所以会报告没有可用位置的错误。(有一天,我们希望Subversion可以更灵活和优雅的处理这种场景。)

注意,即使你没有明确提供peg修订版本或操作修订版本,他们依然是存在的。为了使用的简便,对于工作拷贝项目的缺省peg修订版本是BASE,而版本库URL的缺省值是HEAD。当没有提供操作修订版本时,缺省是与peg修订版本一样。

也就是说很久以前我们创建了我们的版本库,在修订版本1添加我们第一个concept目录,并且在这个目录增加一个IDEA文件与concept相关,在几个修订版本之后,真实的代码被添加和修改,我们在修订版本20,修改这个目录为frabnaggilywort。通过修订版本27,我们有了一个新的概念,所以一个新的concept目录用来保存这些东西,一个新的IDEA文件来描述这个概念,然后经过5年20000个修订版本,就像他们都有一个非常浪漫的历史。

现在,一年之后,我们想知道IDEA在修订版本1时是什么样子,但是Subversion需要知道我们是想询问当前文件在修订版本1时的样子,还是希望知道concepts/IDEA在修订版本1时的那个文件?确定这些问题有不同的答案,并且因为peg修订版本,你可以用两种方式询问。为了知道当前的IDEA文件在旧版本的样子,我们可以运行:

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

     

当然,在这个例子里,当前的IDEA文件在修订版本1中并不存在,所以Subversion给出一个错误,这个上面的命令是长的peg修订版本命令一个缩写,扩展的写法是:

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

     

当执行时,它包含期望的结果。

如果工作拷贝路径或URL中确实有一个at记号,peg修订版本语法是否会导致问题?深刻理解的读者可能会产生这样的疑问。毕竟,svn是如何知道news@11是我的目录树中的一个目录,还是修订版本11的news文件?幸好,svn会一直假定后者。你只需要在路径最后添加一个at符号,例如news@11@svn只关心最后一个at标记,如果遗漏了最后的修订版本号,不会认为不合法。这个法则甚至可以应用到以at结尾的路径—你可以使用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目录,所以我们指定我们希望看到HEADfrabnaggilywort/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和IDEA文件的修订版本20的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.

     

幸运的是,几乎所有的人不会面临如此复杂的情形,但是如果是,记住peg修订版本是帮助Subversion清除混淆的额外提示。