附录 B. 故障解决

目录

共同问题
使用Subversion的问题
每当我尝试访问版本库,我的Subversion客户端挂起。
每当我尝试运行svn,它告诉我工作拷贝已经锁定。
我在查找和打开版本库时得到错误,而我知道我的版本库URL是正确的。
我怎样在file://的URL中指定一个Windows驱动器盘符?
通过网络对Subversion版本库进行写操作发生问题。
在Windows XP下,Subversion服务器有时候看起来发送损坏的数据。
跟踪Subversion客户端和Apache服务器通话最好的方法是什么?
我刚刚编译了二进制分发版本,当我尝试检出Subversion,我得到一个“Unrecognized URL scheme”错误。
为什么svn revert命令要有一个明确的目标?为什么缺省不是递归的?它的行为方式与大多数其它子命令不同。
当我启动Apache,mod_dav_svn抱怨说发现一个“bad database version”,它发现了db-3.X而不是db-4.X。
我在RedHat 9得到“Function not implemented”错误,无法工作,我如何修正这个问题?
为什么日志说通过Apache(ra_dav)提交或导入的文件“(no author)”?
我偶然在Windows得到“Access Denied”错误,它们看起来随即出现。
在FreeBSD,某些操作(特别是svnadmin create)有时会挂起。
我可以在web浏览器看到我的版本库,但是svn checkout给我一个301 Moved Permanently错误。
我尝试察看我的文件的一个老版本,但是svn告诉我“path not found”。

共同问题

在安装和使用Subversion的过程中会有许多问题,有一些在你更加理解Subversion之后会立刻解决,而有一些会引起麻烦,因为你已经习惯于其它版本控制系统的工作方式。也有一些其它的问题不能解决是因为Subversion在一些操作系统上有bug(考虑到Subversion运行系统的广泛性,没有遇到更多已经是一件让人吃惊的事情了)。

下面的列表是从Subversion多年使用过程中编辑出来的,如果你没有在这里发现问题,可以在Subversion网站上察看最新版本的FAQ。如果你还是有问题,可以发送包含你遇到问题详细描述的邮件到[46]

使用Subversion的问题

这里是Subversion的FAQ最流行的问题。

每当我尝试访问版本库,我的Subversion客户端挂起。

你的版本库和数据都没有损坏,如果你的进程直接访问版本库(mod_dav_svn、svnlook、svnadmin或者你通过file://的URL访问),然后它会使用Berkeley DB来访问你的数据。Berkeley DB是一个日志系统,意味着在做一件事之前会记录下来所有的事情,如果你的进程被中断(例如一个终止信号或段错误),这样就会留下一个锁文件,还有一个描述未完成业务的日志文件。任何其它尝试访问数据库的进程会挂起,等待锁文件消失。为了唤醒你的版本库,你需要询问Berkeley DB是否结束工作,或者是恢复数据库到前一个已知的稳定状态。

确定你使用数据库的拥有者和管理者用户来运行这个命令,而不是root或是其它会在db目录产生root拥有文件的用户,这些文件不可以由管理数据库的非root用户打开,通常是你或你的Apache进程。也要确定在恢复时有正确的umask设置,因为如果失败会把允许访问版本库的用户组锁在外面。

简单的运行:

$ svnadmin recover /path/to/repos

一旦这个命令完成,检查版本库db/目录的访问限制。

每当我尝试运行svn,它告诉我工作拷贝已经锁定。

Subversion的工作拷贝,就像Berkeley DB使用日志机制来执行所有的操作,也就是它会在事情发生前记录所有的操作。如果svn在一个动作中被中断,就会留下一个或多个锁文件以及相关的描述未完成动作的日志文件。(svn status会在锁定的目录前面显示一个L。)

任何其它尝试访问工作拷贝的进程会在看到锁定后会提示失败,为了唤醒工作拷贝,你需要告诉客户端完成工作,做为修正,在你的工作拷贝顶级目录运行这个命令:

$ svn cleanup

我在查找和打开版本库时得到错误,而我知道我的版本库URL是正确的。

“每当我尝试访问版本库,我的Subversion客户端挂起。”一节

你也许也遇到了一个版本库访问权限问题,见“支持多种版本库访问方法”一节

我怎样在file://的URL中指定一个Windows驱动器盘符?

版本库的URL

通过网络对Subversion版本库进行写操作发生问题。

如果本地访问的导入工作正常:

$ mkdir test
$ touch test/testfile
$ svn import test file:///var/svn/test -m "Initial import"
Adding         test/testfile
Transmitting file data .
Committed revision 1.

但不是从一个远程主机:

$ svn import test http://svn.red-bean.com/test -m "Initial import"
harry's password: xxxxxxx

svn_error: … The specified activity does not exist.

如果REPOS/dav/目录对httpd进程不是可写的我们会看这些,检查权限来确定Apache的httpd进程可以写访问dav/目录(当然也同样对于db/目录)。

在Windows XP下,Subversion服务器有时候看起来发送损坏的数据。

你需要安装Windows XP Service Pack 1来修正操作系统的TCP/IP堆栈bug,你可以查看http://support.microsoft.com/default.aspx?scid=kb;EN-US;q317949来得到这个Service Pack的所有信息。

跟踪Subversion客户端和Apache服务器通话最好的方法是什么?

使用Ethereal来偷听对话:

注意

如下的指导针对Ethereal的图形化版本,不是应用在命令行版本(二进制文件通常叫做tethereal)。

  • 打开Capture菜单,选择Start。

  • Filter的port输入80,关闭promiscuous模式。

  • 运行Subversion客户端。

  • 点击Stop,你现在已经捕捉了,它看起来像是巨大的行列表。

  • 点击Protocol列来排序。

  • 然后,点击第一个相关的TCP行来选择它。

  • 右键,选择Follow TCP Stream,你会看到Subversion客户端的HTTP对话的请求/响应对。

另一种选择,你可以在客户端的servers运行配置文件中设置一个参数,来允许neon调试信息的出现,neon-debug得数字值是头文件ne_utils.hNE_DBG_*值的组合,设置neon-debug-mask变量为130(例如NE_DBG_HTTP + NE_DBG_HTTPBODY)会导致显示HTTP数据。

你或许也会希望在网络跟踪时关掉压缩,可以通过设置同一个文件的http-compression参数。

我刚刚编译了二进制分发版本,当我尝试检出Subversion,我得到一个“Unrecognized URL scheme”错误。

Subversion使用一个插件系统来允许访问版本库,当前有三种这样的插件:ra_local允许访问本地版本库,ra_dav允许通过WebDAV访问,而ra_svn允许通过svnserve服务器本地或远程访问。当你尝试执行一个Subversion操作,程序会根据URL模式动态的加载一个插件,file://的URL会加载ra_local,而http://的URL会尝试ra_dav。

你看到的错误意味着动态链接器/加载器不能发现需要加载的插件,这通常是因为你使用共享库编译Subversion,然后尝试在没有首先运行make install时运行它。另一个可能的原因是你运行了make install,但是库安装的位置动态链接器/加载器不能识别。在Linux,你可以通过在库目录添加/etc/ld.so.conf并运行ldconfig来允许链接器/加载器找到这些库。如果你不希望这样做,或者是你没有root权限,你可以直接在LD_LIBRARY_PATH环境变量中指定库目录。

为什么svn revert命令要有一个明确的目标?为什么缺省不是递归的?它的行为方式与大多数其它子命令不同。

一句话:它有自己的好处。

Subversion把保护你的数据作为非常高的优先级,对于已经版本化的文件的修改,和预定要添加到版本控制的文件,必须小心对待。

svn revert命令需要一个明确的目标—即使目标只是“.”—是实现这个目的的一个方法。这个要求(同样的还有要求使用--recursive来实现递归的行为)是为了让你清楚自己所做的事情,因为一旦你的文件被恢复,你的本地修改就会永远消失。

当我启动Apache,mod_dav_svn抱怨说发现一个“bad database version”,它发现了db-3.X而不是db-4.X。

你的apr-util链接了DB-3,而svn链接了DB-4,很不幸,DB对象并没有区别。当mod_dav_svn加载到Apache的处理空间,它无法解析针对apr-util的DB-3的对象名称。

解决方案是确定apr-util针对DB-4编译,你可以通过指定apr-util或Apache的选项来完成这一点:"--with-dbm=db4 --with-berkeley-db=/the/db/prefix"。

我在RedHat 9得到“Function not implemented”错误,无法工作,我如何修正这个问题?

这不是Subversion的问题,但是经常影响Subversion用户。

RedHat 9和Fedora分发版本中包括了Berkeley DB库,依赖于为NPTL(the Native Posix Threads Library)内核支持,RedHat得内核提供了内置的支持,但是如果你编译了你的内核,你或许不再有NPTL的支持,所以这种情况下你会看到这样的错误:

svn: Berkeley DB error
svn: Berkeley DB error while creating environment for filesystem tester/db:
Function not implemented

可以用以下的任意一种方法修正这个问题:

  • 重新为你使用的内核编译db4。

  • 使用RedHat 9的内核。

  • 为你使用的内核应用NPTL补丁。

  • 使用最近的(2.5.x)包括NPTL支持的内核。

  • 检查环境变量LD_ASSUME_KERNEL是否设置为2.2.5,如果是,在运行Subversion(Apache)之前取消设置。(在RedHat 9运行Wine或Winex时你通常会设置这个变量)

为什么日志说通过Apache(ra_dav)提交或导入的文件“(no author)”?

如果你允许通过Apache的匿名写访问版本库,Apache从不会要求客户端的用户名,而且在写操作中没有认证,因此Subversion对于谁做的操作一无所知,这导致了这样的日志:

$ svn log
------------------------------------------------------------------------
rev 24:  (no author) | 2003-07-29 19:28:35 +0200 (Tue, 29 Jul 2003)
…

阅读如何添加认证在第 6 章 配置服务器

我偶然在Windows得到“Access Denied”错误,它们看起来随即出现。

这看起来是因为不同的监控文件系统变化(杀毒软件、目录服务和COM+事件通知服务)的Windows服务。这不是Subversion的bug,让修正变得很困难。当前状态的研究总结在http://www.contactor.se/~dast/svn/archive-2003-10/0136.shtml,一个用来减少大多数人发生概率的工作在修订版本7598已经实现。

在FreeBSD,某些操作(特别是svnadmin create)有时会挂起。

这通常是因为系统缺乏可用的信息量,Subversion一次次询问APR产生随机数来创建UUID,特定操作系统会阻止高质量的随机性,你可能需要配置系统从硬盘和网络中断等资源中收集信息,咨询你的系统管理员,明确random(4)rndcontrol(8)怎样影响这些变化。另一个工作区让APR根据/dev/urandom而不是/dev/random编译。

我可以在web浏览器看到我的版本库,但是svn checkout给我一个301 Moved Permanently错误。

这意味着你的httpd.conf错误的配置,通常这个错误发生在你定义Subversion虚拟“location”时使之同时存在于两个不同的范围。

例如,如果你已经以<Location /www/foo>导出了一个版本库,但是你也已经设置了DocumentRoot/www,然后你会陷入麻烦,当请求要得到/www/foo/bar,Apache不知道是去找一个DocumentRoot下的真实文件/foo/bar还是询问mod_dav_svn从/www/foo版本库得到一个文件/bar,通常是前一种情况发生作用,因此得到"Moved Permanently"错误。

解决方案是确定你的版本库的<Location>没有重叠,或者是没有存在于已经作为普通web共享暴露的目录。

我尝试察看我的文件的一个老版本,但是svn告诉我“path not found”。

Subversion的一个好的特性是版本库理解拷贝和重命名,并且保留历史联系。举个例子,如果你拷贝/trunk/branches/mybranch,然后版本库理解为在分支的每个文件都在trunk有个“前辈”。运行svn log --verbose会显示历史拷贝,所以你可以看到重命名:

r7932 | joe | 2003-12-03 17:54:02 -0600 (Wed, 03 Dec 2003) | 1 line
Changed paths:
   A /branches/mybranch (from /trunk:7931)

很不幸,当版本库意识到拷贝和重命名,版本1.0的几乎所有的svn客户端子命令还没有意识到。svn diffsvn mergesvn cat应该理解这些重命名,但是它们没有。它们是1.0之后的特性,举个例子,如果你询问svn diff比较两个早期版本的/branches/mybranch/foo.c,这个命令不会自动理解为实际上我们是要比较两个版本的/trunk/foo.c,因为这个重命名。相反,你会看到一个错误说这个分支路径在早期的修订版本并不存在。

解决所有此类问题的方法是你自己的调查,也就是:需要知道所有的重命名路径,自己使用svn log -v去发现,然后明确地告诉svn客户端,例如,我们不应该运行

$ svn diff -r 1000:2000 http://host/repos/branches/mybranch/foo.c
svn: Filesystem has no item
svn: '/branches/mybranch/foo.c' not found in the repository at revision 1000

...而会运行

$ svn diff -r1000:2000 http://host/repos/trunk/foo.c
...


[46] 记住你所能提供的设置细节和问题的数量与从邮件列表得到答案的可能性成正比,鼓励你包括所有的事情,除了早饭吃了什么和你妈妈的娘家姓。