5. 检验历史

你的版本库就像是一台时间机器。它记录了所有提交的修改,允许你检查文件或目录,以及相关元数据的历史。通过一个 Subversion 命令你可以根据时间或版本号取出一个过去的版本(或者恢复现在的工作副本)。然而,有时候我们只是想看看历史而不想回到历史。

有多个命令可以从版本库为你提供历史数据:

svn diff

显示特定修改的行级详细信息

svn log

展示给你主要信息:每个版本,以及附加在版本上的作者与日期信息和所有路径修改。

svn cat

显示指定版本的某一个文件

svn list

显示指定版本的目录中的文件

5.1. 检查历史修改详情

我们已经看过 svn diff—它使用标准差异文件格式显示区别,我们用它在提交到版本库前显示本地修改。

事实上,svn diff种不同的用法:

  • 检查本地修改

  • 比较工作副本与版本库

  • 比较版本库中的版本

5.1.1. 检查本地修改

像我们看到的,不使用任何参数调用时,svn diff 将会比较你的工作文件与缓存在 .svn原始副本:

$ svn diff
Index: rules.txt
===================================================================
--- rules.txt	(revision 3)
+++ rules.txt	(working copy)
@@ -1,4 +1,5 @@
 Be kind to others
 Freedom = Responsibility
 Everything in moderation
-Chew with your mouth open
+Chew with your mouth closed
+Listen when others are speaking
$

5.1.2. 比较工作副本和版本库

如果传递一个 --revision (-r) 参数,你的工作副本会与版本库中的指定版本比较:

$ svn diff -r 3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt	(revision 3)
+++ rules.txt	(working copy)
@@ -1,4 +1,5 @@
 Be kind to others
 Freedom = Responsibility
 Everything in moderation
-Chew with your mouth open
+Chew with your mouth closed
+Listen when others are speaking
$

5.1.3. 比较版本库中的版本

如果通过 --revision (-r) 传递两个通过冒号分开的版本号,这两个版本会直接比较:

$ svn diff -r 2:3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt	(revision 2)
+++ rules.txt	(revision 3)
@@ -1,4 +1,4 @@
 Be kind to others
-Freedom = Chocolate Ice Cream
+Freedom = Responsibility
 Everything in moderation
 Chew with your mouth open
$

与前一个修订版本比较的更方便办法是使用选项 --change(-c) :

$ svn diff -c 3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt	(revision 2)
+++ rules.txt	(revision 3)
@@ -1,4 +1,4 @@
 Be kind to others
-Freedom = Chocolate Ice Cream
+Freedom = Responsibility
 Everything in moderation
 Chew with your mouth open
$

最后,即使你在本机没有工作副本,还是可以比较版本库的修订版本,只需要在命令行中输入合适的URL:

$ svn diff -c 5 http://svn.example.com/repos/example/trunk/text/rules.txt
…
$

5.2. 产生历史修改列表

找出一个文件或目录的历史信息,需要使用 svn log 命令。svn log 将会给你提供记录,包括:谁对文件或目录作了修改, 哪个版本作了修改, 版本的日期和时间, 还有如果你当时提供了日志信息,也会显示:

$ svn log
------------------------------------------------------------------------
r3 | sally | 2008-05-15 23:09:28 -0500 (Thu, 15 May 2008) | 1 line

Added include lines and corrected # of cheese slices.
------------------------------------------------------------------------
r2 | harry | 2008-05-14 18:43:15 -0500 (Wed, 14 May 2008) | 1 line

Added main() methods.
------------------------------------------------------------------------
r1 | sally | 2008-05-10 19:50:31 -0500 (Sat, 10 May 2008) | 1 line

Initial import
------------------------------------------------------------------------

注意日志信息缺省根据时间逆序排列。如果你希望察看特定顺序的一段修订版本或者单一版本,请使用 --revision (-r) 选项:

表 2.1. 常用日志操作

Command 描述
svn log -r 5:19 Display logs for revisions 5 through 19 in chronological order
svn log -r 19:5 Display logs for revisions 5 through 19 in reverse chronological order
svn log -r 8 只显示版本 8 的日志

你也可以检查单个文件或目录的日志历史。例如:

$ svn log foo.c
…
$ svn log http://foo.com/svn/trunk/code/foo.c
…

这样只会显示这个工作文件(或者 URL)做过修改的版本的日志信息。

如果你希望得到目录和文件更多的信息,你可以对 svn log命令使用选项 --verbose (-v)。因为 Subversion 允许移动和复制文件和目录,所以跟踪路径修改非常重要。在详细模式下,svn log 输出中会包括路径修改的历史:

$ svn log -r 8 -v
------------------------------------------------------------------------
r8 | sally | 2008-05-21 13:19:25 -0500 (Wed, 21 May 2008) | 1 line
Changed paths:
   M /trunk/code/foo.c
   M /trunk/code/bar.h
   A /trunk/code/doc/README

Frozzled the sub-space winch.

------------------------------------------------------------------------

svn log 还有一个选项 --quiet (-q),它会禁止日志信息的主要部分。当 与--verbose 结合使用,仅会显示修改的文件名。

5.3. 浏览版本库

通过使用 svn catsvn list ,你可以在不修改工作副本的情况下查看不同版本的文件和目录的内容。实际上,你甚至也不需要有一个工作副本。

5.3.1. svn cat

如果你只是希望检查一个过去的版本而不希望察看它们的区别,使用svn cat

$ svn cat -r 2 rules.txt
Be kind to others
Freedom = Chocolate Ice Cream
Everything in moderation
Chew with your mouth open
$

你可以重定向输出到一个文件:

$ svn cat -r 2 rules.txt > rules.txt.v2
$

5.3.2. svn list

svn list可以在不下载文件到本地目录的情况下来察看目录中的文件:

$ svn list http://svn.example.com/repo/project
README
branches/
tags/
trunk/

如果你希望察看详细信息,你可以使用--verbose(-v) 参数:

$ svn list -v http://svn.example.com/repo/project
  23351 sally                 Feb 05 13:26 ./
  20620 harry            1084 Jul 13  2006 README
  23339 harry                 Feb 04 01:40 branches/
  23198 harry                 Jan 23 17:17 tags/
  23351 sally                 Feb 05 13:26 trunk/

这些列告诉你文件和目录最后修改的修订版本, 做出修改的用户, 如果是文件还会有文件的大小,最后是修改日期和项目的名字。

[警告] 警告

The svn list command with no arguments defaults to the repository URL of the current working directory, not the local working copy directory. After all, if you want a listing of your local directory, you could use just plain ls (or any reasonable non-Unixy equivalent).

5.4. 获得旧的版本库快照

In addition to all of the previous commands, you can use the --revision (-r) option with svn update to take an entire working copy back in time:[8]

# Make the current directory look like it did in r1729.
$ svn update -r 1729
…
$
[提示] 提示

Many Subversion newcomers attempt to use the preceding svn update example to undo committed changes, but this won't work as you can't commit changes that you obtain from backdating a working copy if the changed files have newer revisions. See 第 3.6 节 “找回删除的项目” for a description of how to undo a commit.

If you'd prefer to create a whole new working copy from an older snapshot, you can do so by modifying the typical svn checkout command. As with svn update, you can provide the --revision (-r) option. But for reasons that we cover in 第 2 节 “Peg 和实施修订版本”, you might instead want to specify the target revision as part of Subversion's expanded URL syntax.

# Checkout the trunk from r1729.
$ svn checkout http://svn.example.com/svn/repo/trunk@1729 trunk-1729
…
# Checkout the current trunk as it looked in r1729.
$ svn checkout http://svn.example.com/svn/repo/trunk -r 1729 trunk-1729
…
$

Lastly, if you're building a release and wish to bundle up your files from Subversion but don't want those pesky .svn directories in the way, you can use svn export to create a local copy of all or part of your repository sans .svn directories. The basic syntax of this subcommand is identical to that of the svn checkout:

# Export the trunk from the latest revision.
$ svn export http://svn.example.com/svn/repo/trunk trunk-export
…
# Export the trunk from r1729.
$ svn export http://svn.example.com/svn/repo/trunk@1729 trunk-1729
…
# Export the current trunk as it looked in r1729. 
$ svn export http://svn.example.com/svn/repo/trunk -r 1729 trunk-1729
…
$


[8] 看到了吧?我们说过Subversion是一个时间机器。