第 3 章 使用指南
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/21.html
现在我们要详细介绍Subversion的使用。读完这一章后,你就能执行几乎所有在日常工作中使用Subversion时所用到的任务了。你会从最初检出你的代码开始,然后到修改和检查改动。你将看到如何把别人的修改引入你的工作副本,检查那些修改,然后解决所有可能的冲突。 Bbs.Svn8.Com
注意,本章不打算写成一个全部Subversion命令的详尽列表,而是对你会碰到的最常用的Subversion任务的一个谈话式的介绍。本章假设你已经读过并且理解了第 2 章 基本概念,熟悉了Subversion的一般模型。对全部命令的完整参考见???
Svn中文网
帮助!在继续读之前,先看一下Subversion最重要的命令:svn help。 Subversion命令行客户程序是自文档化的;任何时候,执行svn help <subcommand> 将给出对subcommand语法,选项和行为的描述。 Www.Svn8.Com
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/14.html
====
你要用svn import把一个新项目导入Subversion的资料库。虽然当你设置你的Subversion服务器时,导入极有可能是首先要做的事, 但是它并不很常用。对导入的详细描述,参加本章稍后“svn import”一节。
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/15.html
========
修订版:号码,关键字和日期,喔!
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/16.html
修订版:号码,关键字和日期,喔!在我们继续之前,你应该知道一点怎样在你的资料库中标识一个特定的修订版。如你在“修订版(Revision)”一节中学到的那样,修订版是资料库在某个特定时刻的“快照”。在你不断提交和增加你的资料库内容时,需要一种机制来标识这些快照。
Bbs.Svn8.Com
为了指定修订版,你要用--revision (-r)这个选项加上你想要的修订版(svn --revision REV),或者你可以指定一个范围,这要用冒号来分隔两个修订版(svn --revision REV1:REV2)。Subversion允许你用号码,关键字,或日期来指定修订版。
参考资料:www.svn8.com
修订版号码当你创建一个新的Subversion资料库时,它从修订版0开始。后来的每次提交使修订版号码增加1。在提交完成时,Subversion客户程序会通知你新的修订版号码: 参考资料:www.svn8.com
$ svn commit --message "Corrected number of cheese slices."
Sending sandwich.txt
Transmitting file data .
Committed revision 3.
Svn8.Com 如果将来某个时候你想参考这个修订版(本章稍后,我们会看到我们怎样和为什么会想这么做),你可以用号码“3”来查阅。 Svn中文网
修订版关键字Subversion客户端程序可以理解一些修订版关键字。这些关键字可用来替代--revision开关需要的整数参数,它们会被Subversion解析成特定的修订版号码。
Svn8.Com
注意在工作副本中的每一个目录都包含一个.svn子目录。对于目录中的每个文件,Subversion都在管理区域中保存一份拷贝。这个拷贝是在你上一次更新你的工作副本后的那个修订版(称为“BASE”修订版)中文件的未修改的(没有关键字展开,没有换行符转换,什么都没改)副本,我们称这个副本为文件的原始拷贝(pristine copy)或者基础文本(text-base)版本,它总是对资料库中文件逐字节的精确拷贝。 参考资料:www.svn8.com
HEAD
资料库中最新的修订版。
BASE
工作副本中条目的“原始的”修订版。 Bbs.Svn8.Com
COMMITTED
在BASE之前(或之内),一个条目被修改的最新的修订版。
参考资料:www.svn8.com
PREV
在一个条目被修改的修订版之前的那个修订版(技术上讲,COMMITTED - 1)。
Svn8.Com
注意PREV,BASE,和 COMMITTED 只能用于查询本地路径,不能用于URL。
Svn8.Com
这儿有一些使用修订版关键字的例子。如果现在不明白这些命令先不要着急,随着本章节的进行我们将解释这些命令。
参考资料:www.svn8.com
$ svn diff --revision PREV:COMMITTED foo.c
# shows the last change committed to foo.c
$ svn log --revision HEAD
# shows log message for the latest repository commit
$ svn diff --revision HEAD
# compares your working file (with local mods) to the latest version
# in the repository.
$ svn diff --revision BASE:HEAD foo.c
# compares your “pristine” foo.c (no local mods) with the
# latest version in the repository
$ svn log --revision BASE:HEAD
# shows all commit logs since you last updated
$ svn update --revision PREV foo.c
# rewinds the last change on foo.c.
# (foo.c's working revision is decreased.)
Svn8.Com 这些关键字帮助你完成很多日常工作,而不需要寻找特定的修订版号码或者记住你的工作副本的准确的修订版。
参考资料:www.svn8.com
修订版日期A 任何你可以指定修订版号码或修订版关键字的地方,你也可以用一对花括号“{}”来指定日期。你甚至可以同时使用日期和修订版来访问一个范围内的修改。
参考资料:www.svn8.com
这儿有一些Subversion可以接受的日期格式的例子。记住使用引号括起那些包含空格的日期。 Www.Svn8.Com
$ svn checkout --revision {2002-02-17}
$ svn checkout --revision {15:30}
$ svn checkout --revision {15:30:00.200000}
$ svn checkout --revision {"2002-02-17 15:30"}
$ svn checkout --revision {"2002-02-17 15:30 +0230"}
$ svn checkout --revision {2002-02-17T15:30}
$ svn checkout --revision {2002-02-17T15:30Z}
$ svn checkout --revision {2002-02-17T15:30-04:00}
$ svn checkout --revision {20020217T1530}
$ svn checkout --revision {20020217T1530Z}
$ svn checkout --revision {20020217T1530-0500}
…
参考资料:www.svn8.com 当你用日期来指定修订版时,Subversion会找到资料库中到那个日期为止的最新的修订版。 Www.Svn8.Com
$ svn log --revision {2002-11-28}
------------------------------------------------------------------------
r12 | ira | 2002-11-27 12:31:51 -0600 (Wed, 27 Nov 2002) | 6 lines
…
Svn8.Com Subversion的时间早一天吗? Svn中文网
如果你指定了一个单独的日期作为修订版而没有指定这天中的时间(例如 2002-11-27),你可能认为Subversion应该给你11月27号的最后的修订版。实际上,你会得到一个26号的,甚至更早的修订版。记住,Subversion将找到资料库中到你给定的时间为止的最新的修订版。如果你给定一个没有时间戳的日期,像2002-11-27,Subversion假设时间是00:00:00,因此寻找最近的修订版不会返回任何27号的东西。
Svn中文网
如果你想把27号包括在你的搜索范围里,你可以指定27号的同时指定时间({"2002-11-27 23:59"}),或者简单的指定到第二天({2002-11-28})。 Svn8.Com
你也可以使用一个日期范围。Subversion会发现这两个日期间的所有修订版,包括这两天在内。 Bbs.Svn8.Com
$ svn log --revision {2002-11-20}:{2002-11-29}
…
Www.Svn8.Com 如我们所指出的,你也可以混合使用日期和修订版。 参考资料:www.svn8.com
$ svn log --revision {2002-11-20}:4040
Svn中文网 用户应该意识到在Subversion中使用日期时的一个微妙的地方,它可能会成为一个很大的障碍。由于一个修订版的时间戳是作为修订版的一个属性存储的,这个属性是不版本化的,可以修改的。修订版时间戳可以被修改成与真正的时间表完全不同,甚至能完全被删除。这会对Subversion内部做日期到修订版的转换带来严重破坏。
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/16.html
========
最初的检出
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/17.html
最初的检出大部分时候,你会从检出你的项目来开始使用Subversion资料库。检出资料库会在你本地机器上创建一个副本。这个副本包含在你命令行中指定的Subversion资料库的HEAD修订版。 Svn中文网
$ svn checkout http://svn.collab.net/repos/svn/trunk
A trunk/subversion.dsw
A trunk/svn_check.dsp
A trunk/COMMITTERS
A trunk/configure.in
A trunk/IDEAS
…
Checked out revision 2499.
Www.Svn8.Com 资料库布局
参考资料:www.svn8.com
I 也许你对上面所有URL中都有的trunk是什么有疑问,它是我们推荐的你的Subversion资料库的布局的一部分。我们会在第 4 章 分支和合并中谈到更多。
Svn8.Com
尽管上面的例子检出的是trunk目录,你也可以很容易的从资料库中检出任何深度的子目录,只要在URL中指定子目录: Bbs.Svn8.Com
$ svn checkout http://svn.collab.net/repos/svn/trunk/doc/book/tools
A tools/readme-dblite.html
A tools/fo-stylesheet.xsl
A tools/svnbook.el
A tools/dtd
A tools/dtd/dblite.dtd
…
Checked out revision 2499.
Svn中文网 既然Subversion使用“拷贝-修改-合并”模型,而不是“锁定-修改-解锁”(参加第 2 章 基本概念),那么你现在已经可以开始修改你工作副本中的文件和目录了。你的工作副本就像你系统上其他的文件和目录集合一样。你可以编辑和修改他们,移动他们,你甚至能删除整个工作副本并忘掉它。
Svn8.Com
注意虽然工作副本“就像其他在你系统上的文件和目录集合”,但是如果你要重新安排你工作副本中的任何东西,你得让Subversion知道。如果你想复制或者移动工作副本中的一项,你应该使用 svn copy 或者 svn move命令,而不是你的操作系统提供的复制和移动命令。在本章稍后,我们会谈到更多。 Svn8.Com
除非你准备好要提交一个新文件或目录或者提交对现有项的修改,否则,不需要通知Subversion服务器你已经作了什么。 Svn8.Com
.svn有什么用? Www.Svn8.Com
工作副本中的每个目录包含一个管理区域,即一个命名为.svn的子目录。通常,使用列目录命令不会显示这个子目录。但是它确实是非常重要的。不管你做什么,都不要删除或者修改在管理区域中的任何东西。Subversion依靠它来管理你的工作副本。 Svn8.Com
你可以仅使用资料库URL作为唯一参数来检出一个工作副本,你也可以在你的资料库URL后面指定一个目录。这样,你的工作副本会被放在你指定的新目录里。例如: 参考资料:www.svn8.com
$svn checkout http://svn.collab.net/repos/svn/trunk subv
A subv/subversion.dsw
A subv/svn_check.dsp
A subv/COMMITTERS
A subv/configure.in
A subv/IDEAS
…
Checked out revision 2499.
Www.Svn8.Com 以上命令会把你的工作副本放到一个名为subv的目录里,而不是像前面那样放到trunk目录下 Www.Svn8.Com
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/17.html
=======
基本工作流程
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/18.html
Subversion有大量特性,选项,丰富多样,但在日常基本工作中,更可能的是你仅仅用到很少的几个。在本节,我们浏览一下你在日常工作中使用Subversion最常会作的事。 Www.Svn8.Com
典型的工作流程看起来像这样: Svn中文网
更新你的工作副本
Bbs.Svn8.Com
svn update
参考资料:www.svn8.com
做修改 参考资料:www.svn8.com
svn add Www.Svn8.Com
svn delete Bbs.Svn8.Com
svn copy Svn8.Com
svn move Svn中文网
检查你的改动 Bbs.Svn8.Com
svn status Svn中文网
svn diff Svn中文网
svn revert
合并别人的改动 Www.Svn8.Com
svn merge 参考资料:www.svn8.com
svn resolved Svn中文网
提交你的改动
Svn中文网
svn commit Bbs.Svn8.Com
更新你的工作副本当你在一个团队中为一个项目工作时,你会想要更新你的工作拷贝来获取那些你上次更新以来其他开放人员对项目做的新改动。使用 svn update会使你的工作副本和资料库中最新的修订版同步。 Www.Svn8.Com
$ svn update
U foo.c
U bar.c
Updated to revision 2.
Bbs.Svn8.Com 这种情况表明在你上一次更新后,别人检入了对foo.c 和 bar.c的修改。 Subversion已经更新了你的工作副本,加入了那些改动。
Svn8.Com
让我们更仔细的查看一下svn update的输出。当服务器发送改动到你的工作副本时,会在每项前显示一个字母代码,让你知道Subversion 在同步你的工作副本时对它作了什么动作: 参考资料:www.svn8.com
U foo
文件foo被(Updated)更新了(从服务器接受修改)。 Svn8.Com
A foo
文件或目录foo被加到了(Added)你的工作副本中。
Svn8.Com
D foo
文件或目录foo被从你的工作副本删除了(Deleted)。 参考资料:www.svn8.com
R foo
你工作副本中的文件或目录foo被替换了(Replaced)。就是说,foo被删除了,一个新的同名项被添加了。虽然它们名字相同,但是资料库认为他们是不同的对象并有不同的历史纪录。 Svn中文网
G foo
文件foo从资料库收到了修改,但是你的本地副本已经被你修改了。或者是因为这些修改不交叉,或者是因为修改完全相同, Subversion已经成功地,毫无问题地把资料库中的修改合并(merGed)了到了文件中。 参考资料:www.svn8.com
C foo
文件 foo从服务器接收到了冲突(Conflicting)的改动。来自服务器的改动和你对文件的改动有直接重叠。即使这样也不用急。这些交叠需要人来解决;在本章稍后我们会讨论这一点。
Svn中文网
修改你的工作副本现在你可以开始工作,修改你的工作副本了。通常选择做一个(或一些)特定的修改,比如写一个新的特性,解决一个Bug等比较好。这时可能用到的Subversion的命令是:svn add, svn delete, svn copy, and svn move。然而,如果你仅仅编辑那些已经在Subversion中的文件,你可能直到提交都不需要这些命令。你可以在你的工作副本中做的修改: Svn8.Com
文件修改
这是最简单的那种的修改。你不需要告诉Subversion你打算改一个文件;只要改就行了。Subversion能自动探测哪些文件被修改过了。
Svn8.Com
树修改
你可以让Subversion把文件和目录标记为将要删除,增加,复制,或移动。虽然这些修改在你的工作副本中立即生效,但是直到你提交它们才会发生在资料库里。
Svn中文网
修改文件时,可以使用你的文本编辑器,字处理器,图像编辑程序,或者其他任何你通常使用的工具。Subversion处理二进制文件就像处理文本文件一样容易——也同样高效。 Www.Svn8.Com
下面是对四个Subversion子命令的一个概述。这些命令是你在修改树时最常用的。(我们将稍后谈到 svn import 和 svn mkdir) Bbs.Svn8.Com
svn add foo
使文件,目录或者符号连接foo预定将要被添加到资料库。在你下一次提交时,foo 将会成为它父目录的子项。注意:如果foo是一个目录,所有在foo下的东西都会被预定要添加。如果你只想添加foo本身,要用--non-recursive (-N)开关。
svn delete foo
预定文件目录或者符号链接foo要从资料库删除。如果foo是一个文件或者一个连接,它马上就从你的工作副本删除。如果foo是一个目录,它不被删除,但是Subversion预定它要被删除。当你提交你的修改时,foo会被从你的工作副本和资料库删除。 [1]
svn copy foo bar
创建foo的一个名为bar的拷贝。bar自动被预定添加。当bar在下次提交中被添加时,他的复制历史被记录了(即记录它原本来自于foo)。 svn copy不会创建中间目录。
Bbs.Svn8.Com
svn move foo bar
这个命令和运行svn copy foo bar; svn delete foo完全一样。就是说,bar作为 foo的一个拷贝被预定添加,同时foo被预定删除。 svn move不会创建中间目录。
不用工作副本而修改资料库
Svn中文网
在本章较早时,我们说过你必须提交所有你做的修改,来使资料库反映出这些改动。这不完全对——有 一些用例直接把树修改提交到资料库。这只有在一个子命令直接在一个URL而不是工作副本路径上操作时发生。特别是,svn mkdir,svn copy,svn move,and svn delete 的某些特定用法可用于URL。 Svn8.Com
URL操作之所以这样是因为在工作副本中的操作可以使用工作副本作为某种“集散地”,从而可以在提交到资料库前存放修改。在URL上的操作没有这样的奢侈品,因此当你直接在URL上操作时,上面的任何操作代表了一次立即提交。
Bbs.Svn8.Com
检查你的修改一旦你完成了修改,你需要把它们提交到资料库,但是在这么做之前,看一下究竟那些地方被修改了通常是个好主意。经过提交前对修改的检查,你能写出更准确的日志信息。也可能你会发现你无意中修改了一个文件,从而有机会在提交前取消这些改动。另外,这是一个在发布前回顾和细查那些改动的好机会。你可以使用svn status,svn diff和 svn revert命令来仔细查看究竟做了那些修改。前两个命令用来发现你的工作副本中那些文件和目录修改了,第三个命令用来取消一些(或者全部)修改。 Www.Svn8.Com
Subversion已经对帮助你完成这样的任务作了优化,可以在不和资料库通信的情况下完成很多工作。详细的说,对每个在.svn区域中置于版本控制下的文件,你的工作副本会秘密缓存一个“原始”的拷贝。有了这个拷贝,Subversion可以很快地显示你的工作文件被怎样修改了,甚至允许你不连接资料库而撤销这些修改。
svn status你可能用svn status比任何别的Subversion命令都要多。
CVS 用户:停用更新!
Www.Svn8.Com
你可能习惯于用cvs update来查看你对你的工作副本作了那些修改。svn status 会给你需要注意的所有工作副本中的修改信息——不需要访问资料库或者潜在地引入别人发布的新改动。
Svn中文网
在Subversion里,update命令只做更新——它用从上次更新以来所有提交到资料库的修改来更新你的工作副本。你必须打破用update来查看你在本地作的修改的习惯。 Svn8.Com
如果你在你的工作副本的顶层目录执行不带参数的svn status命令,它会检测所有文件和树的修改。下面是一些不同的 svn status命令会返回的状态码的例子。(注意,#后的文字不会被svn status打印)
Bbs.Svn8.Com
L abc.c # svn has a lock in its .svn directory for abc.c
M bar.c # the content in bar.c has local modifications
M baz.c # baz.c has property but no content modifications
X 3rd_party # this dir is part of an externals definition
? foo.o # svn doesn't manage foo.o
! some_dir # svn manages this, but it's either missing or incomplete
~ qux # versioned as file/dir/link, but type has changed
I .screenrc # svn doesn't manage this, and is configured to ignore it
A + moved_dir # added with history of where it came from
M + moved_dir/README # added with history and has local modifications
D stuff/fish.c # this file is scheduled for deletion
A stuff/loot/bloo.h # this file is scheduled for addition
C stuff/loot/lump.c # this file has conflicts from an update
S stuff/squawk # this file or dir has been switched to a branch
Svn8.Com 在这个输出格式中,svn status打印出5列字符,跟着是几个空格符,跟着是一个文件或目录名。第一列表明了一个文件或目录和(或)它的内容的状态。会在这里打出的代码有: 参考资料:www.svn8.com
A item
文件,目录或者符号连接item已经被预定要添加到资料库。
Svn中文网
C item
文件item处在冲突状态中。就是说,更新时从服务器接收到的改动和你对工作副本作的本地改动交叠了。你必须在把你的修改提交到资料库前解决这些冲突。
D item
文件,目录或者符号连接item已经被预定要从资料库删除。
参考资料:www.svn8.com
M item
文件的item的内容已经被修改了。
Svn中文网
X item
目录item没有版本化,但和一个Subversion 外部定义相关。更多关于外部定义的知识,参见 ???. Svn中文网
? item
文件,目录或者符号连接item没有被置于版本控制之下。你可以传递--quiet (-q)参数给svn status命令,或者在父目录上设置svn:ignore属性,从而不显示这个问号。关于忽略文件的更多信息,参见???。 Svn8.Com
! item
文件,目录或者符号连接item在版本控制中,但是被丢失了或者有些不完整。如果这个项被非Subversion命令删除会导致丢失。如果是一个目录, 如果你打断了一次检出或者更新,它可能会不完整。只要用svn update命令就可以从资料库中重新取回这个文件或目录,或者使用 svn revert file可以恢复一个丢失的文件。
Bbs.Svn8.Com
~ item
文件,目录或者符号连接item在资料库中是某种类型的对象,但是和你工作副本中的不是同一种。例如,可能Subversion资料库中有个文件, 但你没有使用svn delete 和 svn add 命令而在本地删除了它并创建了一个同名的目录,。
I item
文件,目录或者符号连接item没有置于版本控制之下,Subversion被配置成在执行svn add,svn import和 svn status操作中忽略它。关于忽略文件的更多信息,参见???。注意,这个符号只有在你传递--no-ignore选项给svn status时才显示,否则文件会被忽略,根本不列出来。 参考资料:www.svn8.com
第二列表明了一个文件或目录的属性集的状态(更多的关于属性的信息参见???)。如果M出现在第二列,表明属性集被修改了,否则会打印一个空白符。
参考资料:www.svn8.com
第三列只可能显示空白符或一个L,意味着Subversion已经在.svn工作区里锁定了这个文件。如果你在一个正在执行svn commit 的目录下运行svn status,你会看到这个L——可能这时你在编辑日志文件。如果Subversion没有在运行中,那大概是Subversion进程被中断了,锁需要用svn cleanup(本章稍后会更多涉及这个命令)来解除。
第四列只可能显示空白符或者一个+,意味着这个文件或者目录被预定添加,或者被带着附加的历史修改。这通常发生在当你svn move 或 svn copy一个文件或目录时。如果你看到A +,这意味着这一条目被预定带着历史纪录添加。它可能是一个文件,或者一个被复制目录的根。+意味着这个是一个预定被添加的子树的一部分,就是说,它的父目录被复制了,它只是跟着一起走。 M +意味着这个是一个预定被带着历史纪录添加的子树的一部分,同时 它有本地改动。当你提交时,首先父目录被带着历史纪录添加(复制),这意味着这个文件将自动出现在拷贝中。然后本地修改将被上载到拷贝中。
Svn8.Com
第五列只可能显示空白符,或者是一个S。这表明这个文件或目录已经被从工作副本路径切换(使用 svn switch)到一个分支里。
Svn中文网
如果你传递一个指定的路径给svn status,它将只给出关于这个条目的信息: Svn8.Com
$ svn status stuff/fish.c
D stuff/fish.c
参考资料:www.svn8.com svn status也有一个--verbose (-v)选项,它将显示你工作副本中 每一个条目的状态,即使它没有被修改。
Svn中文网
$ svn status --verbose
M 44 23 sally README
44 30 sally INSTALL
M 44 20 harry bar.c
44 18 ira stuff
44 35 harry stuff/trout.c
D 44 19 ira stuff/fish.c
44 21 sally stuff/things
A 0 ? ? stuff/things/bloo.h
44 36 harry stuff/things/gloo.c
Www.Svn8.Com 这是svn status输出的“长形式”。第一列仍旧一样,但是第二列显示的是这个条目的工作修订版。第三和第四列分别显示了本项上次被修改的修订版和谁修改了它。
Svn8.Com
上面这些对svn status的使用都不会连接资料库,它们仅在本地工作,只要比较.svn 目录中的元数据和工作副本中的数据。最后,有一个--show-updates (-u)选项,它连接资料库来添加关于哪些东西过时了的信息。 参考资料:www.svn8.com
$ svn status --show-updates --verbose
M * 44 23 sally README
M 44 20 harry bar.c
* 44 35 harry stuff/trout.c
D 44 19 ira stuff/fish.c
A 0 ? ? stuff/things/bloo.h
Status against revision: 46
Svn8.Com 注意:这两个星号表明,如果你这时执行svn update,你将接收到README 和 trout.c的修改。这给了你一些很有用的信息——你将需要更新并得到服务器上的改动,否则资料库将拒绝你的提交,因为你的文件过时了(稍后有更多关于这个主题的信息)。 参考资料:www.svn8.com
svn diff另一个检查你的修改的办法是使用svn diff命令。你能精确的发现你修改的东西,只要执行不带参数的svn diff,这将用标准化的diff格式打印文件改动: [2]
Svn中文网
$ svn diff
Index: bar.c
===================================================================
--- bar.c (revision 3)
+++ bar.c (working copy)
@@ -1,7 +1,12 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>
int main(void) {
- printf("Sixty-four slices of American Cheese.../n");
+ printf("Sixty-five slices of American Cheese.../n");
return 0;
}
Index: README
===================================================================
--- README (revision 3)
+++ README (working copy)
@@ -193,3 +193,4 @@
+Note to self: pick up laundry.
Index: stuff/fish.c
===================================================================
--- stuff/fish.c (revision 1)
+++ stuff/fish.c (working copy)
-Welcome to the file known as 'fish'.
-Information on fish will be here soon.
Index: stuff/things/bloo.h
===================================================================
--- stuff/things/bloo.h (revision 8)
+++ stuff/things/bloo.h (working copy)
+Here is a new file to describe
+things about bloo.
参考资料:www.svn8.com svn diff命令通过比较你的工作文件和缓存在.svn区中的“原始的” 拷贝来产生输出。预定要添加的文件被显示为所有文本都是新加的,预定要删除的文件被显示为所有文本都被删除。 Www.Svn8.Com
输出以标准化 diff 格式输出。就是说:删除的行以-开头,添加的行以+开头。 svn diff也打印文件名和偏移量这样对patch程序有用的信息。这样使你能把diff输出重定向到一个文件中来产生“补丁(patch)”。 参考资料:www.svn8.com
$ svn diff > patchfile
Svn中文网 例如,在提交前,你可以用电子邮件把补丁文件发送给另一个开发者来检查或者测试。
参考资料:www.svn8.com
svn revert现在假设你看到了以上的diff输出,而且察觉到你对README的修改是错的;可能你不小心在你的编辑器里把文字输错了文件。 Bbs.Svn8.Com
这是一个极好的使用svn revert的机会。
$ svn revert README
Reverted 'README'
Svn中文网 Subversion用.svn区里缓存的“原始的”文件覆盖文件,从而把它恢复到修改前的样子。但是也要注意到svn revert可以撤销任何 预定操作——例如,你可以决定你不想添加某个文件了: Svn中文网
$ svn status foo
? foo
$ svn add foo
A foo
$ svn revert foo
Reverted 'foo'
$ svn status foo
? foo
Bbs.Svn8.Com 注意svn revert ITEM和从你的工作副本中删除ITEM,然后执行svn update -r BASE ITEM效果完全一样。然而,如果你要恢复一个文件,svn revert有一个非常值得注意的特性——它恢复文件不需要和资料库通信。 Www.Svn8.Com
或者,可能你错误的把一个文件从版本控制中拿掉了:
Svn8.Com
$ svn status README
README
$ svn delete README
D README
$ svn revert README
Reverted 'README'
$ svn status README
README
Svn中文网 看那,妈妈! 没有网络!
Www.Svn8.Com
所有这三个命令(svn status,svn diff 和 svn revert)能在没有任何网络访问的情况下使用。当你在一个没有网络的地方时,比如旅行途中在飞机上,在通勤列车上或在海滩上度假,这使得管理你正在进行的修改变的很容易。 Bbs.Svn8.Com
Subversion依靠在.svn管理区域中保存每个版本化文件的一个私有缓存来做到这点。这使得Subversion能报告和恢复对这些文件的本地修改而不需要网络访问。这个缓存(称作“text-base基准文本”)也使Subversion 在提交到服务器时能用压缩的、对原始版本的变化量(或“差”)的方式发送用户的本地修改。有这个缓存是个很大的优势——即使你有一个很快的网络连接,只发送修改也比发送整个文件到服务器快多了。初看起来,这似乎没那么重要,但是想象一下如果你要提交对一个400M的文件中一行的修改而不得不发送整个文件到服务器的后果! Bbs.Svn8.Com
解决冲突(合并别人的修改)我们已经看到svn status -u怎样预报冲突。设想你执行了svn update并看到一些有趣的现象: Svn8.Com
$ svn update
U INSTALL
G README
C bar.c
Updated to revision 46.
Svn中文网 标记U和G没有什么好关心的;这些文件干净利索的吸收了来自资料库的修改。标记为U的文件没有本地修改,而是被资料库中的修改更新(Updated)了。G 代表合并(merGed),这意味着本地文件被修改了,但是来自于资料库的改动和本地修改不重叠。 参考资料:www.svn8.com
但是C代表冲突,这意味着来自服务器的修改和你的修改重叠了,现在你必须手工来选择它们。
任何冲突发生时,通常会有三样东西来帮助你注意到和解决这冲突: Svn中文网
Subversion在更新时打印C,并记录这个文件是处在冲突状态。 Svn中文网
如果Subversion认为这个文件可以被合并,它会放置一个conflict markers冲突标记——用来划定“边界”的特殊的字符串—— 到这个文件中,以使重叠区域可被看到。(Subversion使用svn:mime-type属性来决定一个文件是否能在上下文中基于行来合并。参见???) Svn8.Com
对每个冲突的文件,Subversion会在你的工作副本里放三个额外地没有版本化的文件。
参考资料:www.svn8.com
filename.mine
这是在你更新工作副本前存在于你的工作副本中的文件——就是说,没有冲突标记。这个文件只有你最后的修改。(如果Subversion认为这个文件没法被合并,那么.mine文件不会被创建,反正它将和你的工作文件一样。)
参考资料:www.svn8.com
filename.rOLDREV
这是你更新工作副本前的BASE修订版的文件。就是说,在你做最后的编辑前检出的文件。
参考资料:www.svn8.com
filename.rNEWREV
这个是当你更新了你的工作副本时,Subversion客户程序刚刚从服务器接收到的文件。这个文件对应与资料库中的HEAD修订版。
Svn8.Com
这里OLDREV是在你.svn的文件的修订版号, NEWREV是资料库中HEAD的修订版号。
Bbs.Svn8.Com
例如,Sally修改了资料库中的文件sandwich.txt。Harry刚修改了自己工作副本中的这个文件并且检入了它。 Sally在检入前更新她的工作副本并发现了一个冲突: Svn中文网
$ svn update
C sandwich.txt
Updated to revision 2.
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2
Bbs.Svn8.Com 这时,Subversion 将不允许你提交文件sandwich.txt,直到三个临时文件被删除。
Svn8.Com
$ svn commit --message "Add a few more things"
svn: Commit failed (details follow):
svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict
Svn8.Com 如果你发现一个冲突,你需要做下面三件事之一: 参考资料:www.svn8.com
“手工”合并冲突的文本(检查并编辑文件中的冲突标记)。 Svn中文网
用临时文件中的某个覆盖你的工作文件。 Bbs.Svn8.Com
执行svn revert <filename>来扔掉你的所有本地修改。
Bbs.Svn8.Com
一旦你解决了冲突,你要执行svn resolved让Subversion知道。这个命令删除那三个临时文件并让Subversion不再认为那个文件在冲突状态。 [3] Svn中文网
$ svn resolved sandwich.txt
Resolved conflicted state of 'sandwich.txt'
Svn8.Com 手动合并冲突当你第一次尝试的时候,手动合并冲突可能很难,但在有了些实践后,它就易如反掌了。 Bbs.Svn8.Com
这儿有个例子。由于沟通不好,你和你的合作者Sally,同时编辑了文件sandwich.txt。Sally 提交了它的修改,当你更新工作副本时,你发现一个冲突。我们将不得不比编辑sandwich.txt来解决冲突。首先,我们来看一下文件:
Svn中文网
$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread
Svn8.Com 由小于号,等号和大于号组成的字符串就是冲突标记,他们不是真正冲突数据的一部份。你只要确认在下次提交前从文件中删除他们。在头两个标记行之间的文字是冲突区域里属于你的修改的部分:
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Svn中文网 在第二和第三个标记行之间的文字来自Sally的提交: Svn中文网
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Svn中文网 通常,你不会只是想删除冲突标记和Sally的修改——当三明治送达但不是她想要的那种时她会非常吃惊的—— 因此,这是你应该拿起电话或者走过去,向Sally解释不可能从意大利熟食店买到泡菜。[4] 一旦你们在修改上达成一致,你可以检入了,编辑你的文件并且删除冲突标记。 Svn8.Com
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread
Bbs.Svn8.Com 现在,执行svn resolved,然后你就可以提交你的修改了:
参考资料:www.svn8.com
$ svn resolved sandwich.txt
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
Www.Svn8.Com 记住,如果你编辑冲突文件时一时糊涂了,你总是可以参考Subversion在工作副本中为你创建的三个文件 ——包括了你更新前的文件。你甚至能用第三方的交互式合并工具检查这三个文件。 Bbs.Svn8.Com
用一个文件覆盖你的工作文件如果你发现一个冲突并决定放弃你的修改,你可以简单的用Subversion创建的临时文件之一覆盖你工作副本中的文件。
Svn中文网
$ svn update
C sandwich.txt
Updated to revision 2.
$ ls sandwich.*
sandwich.txt sandwich.txt.mine sandwich.txt.r2 sandwich.txt.r1
$ cp sandwich.txt.r2 sandwich.txt
$ svn resolved sandwich.txt
参考资料:www.svn8.com 使用svn revert如果你发现一个冲突,检查后决定你要放弃你的修改并重新编辑文件,只要撤回你的修改: Www.Svn8.Com
$ svn revert sandwich.txt
Reverted 'sandwich.txt'
$ ls sandwich.*
sandwich.txt
Svn中文网 注意,当你恢复一个冲突文件时,你不一定要执行svn resolved。 Www.Svn8.Com
现在你准备好检入你的修改了。注意svn resolved不像我们在本章介绍过的其他命令,它总是需要一个参数。在任何情况下,你都要小心,只在你确定你已经解决了冲突时才运行svn resolved,一旦临时文件被删除了,即使文件还包含冲突标记,Subversion也允许你提交它。
Svn8.Com
提交你的修改终于!你的编辑完成了,你已经合并了所有来自服务器的修改,你已经做好把你的修改提交到资料库的准备了。
Bbs.Svn8.Com
svn commit把你的所有修改发送到资料库。当你提交一个修改,你要提供一个日志消息来描述你的修改。你的日志消息会被附加到你创建的新修订版上。如果你的日志消息简短,你可以使用--message (或 -m)在命令行中提供:
$ svn commit --message "Corrected number of cheese slices."
Sending sandwich.txt
Transmitting file data .
Committed revision 3.
Bbs.Svn8.Com 然而,如果在你工作时以已经编写了日志消息,你可以告诉Subversion从一个文件来得到消息,这要用--file选项传递文件名: Svn中文网
$ svn commit --file logmsg
Sending sandwich.txt
Transmitting file data .
Committed revision 4.
Svn8.Com 如果你既没有指定--message,也没有指定--file,Subversion会自动运行你喜好的编辑器(参见???中editor-cmd一节)来让你编写一个日志。
Svn8.Com
提示如果你在你的编辑器中写提交消息时决定取消你的提交,你只要退出你的编辑器而不保存修改就行了。如果你已经保存了提交消息,只要删除文字再次保存。 Bbs.Svn8.Com
$ svn commit
Waiting for Emacs...Done
Log message unchanged or not specified
a)bort, c)ontinue, e)dit
a
$
Svn8.Com 资料库不知道也不关心你的提交作为一个整体是否有意义;它只检查确认在你没有看资料库时,其他人没有修改过你修改了的那些文件。如果有人这么做了,整个提交会失败,并有一个消息通知你,你的某个或某些文件过时了。 Www.Svn8.Com
$ svn commit --message "Add another rule"
Sending rules.txt
svn: Commit failed (details follow):
svn: Out of date: 'rules.txt' in transaction 'g'
Bbs.Svn8.Com 这时,你需要运行svn update,处理更新结果中的所有合并和冲突,然后再次尝试提交。 Www.Svn8.Com
到这里已经探讨了使用Subversion的基本工作流程。Subversion有很多别的特性,你可用它们来管理的你的资料库和工作副本,但即时只使用我们到本章这里为止讨论过的命令,你也能很轻松的工作。 Svn8.Com
--------------------------------------------------------------------------------
[1] 当然,没有什么会被从资料库完全删除——仅仅是从资料库的HEAD修订版删除了。你可以取回所有你删除的东西,只要检出(或更新你的工作副本)你做删除前的一个修订版就行了。 Www.Svn8.Com
[2] Subversion使用内置的diff引擎,缺省情况下以标准化diff格式输出。如果你想让diff用不同的格式输出,可以指定一个外部的diff 程序,这需要使用--diff-cmd选项,并用--extensions来传递任何你希望的标志。例如,要检查文件foo.c本地差别,忽略空格,使用上下文输出格式,可使用这样的命令svn diff --diff-cmd /usr/bin/diff --extensions '-bc' foo.c。
Svn中文网
[3] 你可以自己删掉那些临时文件,但既然Subversion能帮你做,你何必自己做呢?我们认为不必。 Svn8.Com
[4] And if you ask them for it, they may very well ride you out of town on a rail.
Svn8.Com
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/18.html q
=========
检查历史
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/19.html
检查历史如前所述,资料库像一个时间机器。它保存所有提交过的修改的纪录,并允许你浏览历史,你可以检查文件和目录的以前的版本以及伴随它们的元数据。只使用一个Subversion 命令,你就能检出和过去某个日期或修订版完全相同的资料库(或者恢复一个存在的工作副本)。然而,有时你只是想窥视过去,而不是回到过去。
Svn8.Com
有几个命令能为你提供资料库中的历史数据:
参考资料:www.svn8.com
svn log
给你概括的信息:附加到修订版上的日志消息,和每个消息的修改路径。
参考资料:www.svn8.com
svn diff
给你一个文件随着时间如何变化的特定细节。
参考资料:www.svn8.com
svn cat
这用来取出存在于某个修订版中的任意文件并显示在你的屏幕上。
参考资料:www.svn8.com
svn list
显示任意给定修订版中某个目录的文件列表。 参考资料:www.svn8.com
svn log要查看一个文件或目录的历史信息,使用svn log命令。svn log将提供提供给你一个纪录,内容包括谁修改了文件或目录,在哪个修订版修改的,这个修订版的时间和日期,如果有的话,还包括一起提交的日志消息。 Bbs.Svn8.Com
$ svn log
------------------------------------------------------------------------
r3 | sally | Mon, 15 Jul 2002 18:03:46 -0500 | 1 line
Added include lines and corrected # of cheese slices.
------------------------------------------------------------------------
r2 | harry | Mon, 15 Jul 2002 17:47:57 -0500 | 1 line
Added main() methods.
------------------------------------------------------------------------
r1 | sally | Mon, 15 Jul 2002 17:40:08 -0500 | 1 line
Initial import
------------------------------------------------------------------------
Svn8.Com 注意,日志消息缺省以时间倒序打印。如果你想用特定的顺序看修订版的不同范围,或者只是某一个修订版,要使用--revision (-r)选项。
$ svn log --revision 5:19 # shows logs 5 through 19 in chronological order
$ svn log -r 19:5 # shows logs 5 through 19 in reverse order
$ svn log -r 8 # shows log for revision 8
Www.Svn8.Com 你也可以检查单一文件或目录的日志历史。例如: 参考资料:www.svn8.com
$ svn log foo.c
…
$ svn log http://foo.com/svn/trunk/code/foo.c
…
Www.Svn8.Com 这样将只显示工作文件曾被修改的那些修订版的日志消息。
参考资料:www.svn8.com
如果你想得到关于一个文件或目录的更多信息,可以使用svn log的--verbose (-v)选项。因为Subversion允许你移动和复制文件,能跟踪文件系统路径的改变很重要,所以在verbose模式下,svn log在输出中包括了一个修订版中路径修改的列表。 Svn中文网
$ svn log -r 8 -v
------------------------------------------------------------------------
r8 | sally | 2002-07-14 08:15:29 -0500 | 1 line
Changed paths:
M /trunk/code/foo.c
M /trunk/code/bar.h
A /trunk/code/doc/README
Frozzled the sub-space winch.
------------------------------------------------------------------------
参考资料:www.svn8.com 为什么svn log给我一个空白的响应? Bbs.Svn8.Com
在使用了Subversion一段时间后,大部分用户将会遇到这样的情况: 参考资料:www.svn8.com
$ svn log -r 2
------------------------------------------------------------------------
$
Www.Svn8.Com 乍一看,好像是出错了。但回忆一下,修订版是在资料库范围内的,svn log在资料库中的一个路径上操作。如果你没有指定路径, Subversion使用当前的工作路径作为缺省目标。因此,如果你在工作副本的一个子目录下操作,这时尝试去查看一个当前目录和目录下的东西都没有修改过的修订版,Subversion 会给你一个空的日志。如果你想查看在这个修订版有什么东西被修改了,试着把svn log指向你资料库中最顶层的URL,就像这样:svn log -r 2 http://svn.collab.net/repos/svn。 参考资料:www.svn8.com
svn diff之前我们已经看到svn diff——它用标准化diff格式显示文件的差异;通常在提交到资料库前,用它来显示我们工作副本中的本地修改。 Svn8.Com
事实上,svn diff有三不同的使用方法: Svn8.Com
检查本地修改
参考资料:www.svn8.com
比较你的工作副本和资料库
比较资料库和资料库 参考资料:www.svn8.com
检查本地修改像我们看到的,调用不带参数的svn diff将比较你的工作文件和缓存在.svn区域的“原始”文件。 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
$
Www.Svn8.Com 比较工作副本和资料库如果指定单个--revision (-r)号,那么会拿你的工作副本和资料库中指定的修订版作比较。 Svn8.Com
$ svn diff --revision 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
$
Bbs.Svn8.Com 比较资料库和资料库如果通过--revision (-r)指定两个用冒号隔开的修订版号,那么会直接比较这两个修订版号。
Svn8.Com
$ svn diff --revision 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
$
Svn中文网 你不仅可以用svn diff来比较你工作副本和资料库中的文件,而且如果你给一个URL参数,也可以在没有工作副本的情况下,检查资料库中两个条目的差别。这个在你本地机器上没有工作副本而又希望检查修改时特别有用。 Svn中文网
$ svn diff --revision 4:5 http://svn.red-bean.com/repos/example/trunk/text/rules.txt
…
$
Bbs.Svn8.Com svn cat如果你想检查一个文件的较早版本而不必是两个文件的不同。你可以使用svn cat: 参考资料:www.svn8.com
$ svn cat --revision 2 rules.txt
Be kind to others
Freedom = Chocolate Ice Cream
Everything in moderation
Chew with your mouth open
$
参考资料:www.svn8.com 你也可以直接把输出重定向到一个文件: Bbs.Svn8.Com
$ svn cat --revision 2 rules.txt > rules.txt.v2
$
Svn8.Com 你可能疑惑为什么我们不就用svn update --revision来把文件更新为旧的版本。我们宁愿用svn cat有几个原因:
参考资料:www.svn8.com
首先,你可能想用外部diff程序来查看这两个不同修订版中文件的差别(可能是用图形化的程序,或者可能你的文件格式特殊导致标准化的diff输出没有意义)。在这种情况下,你需要抓取旧版文件的一个拷贝,把它重定向到一个文件,然后把它和你工作副本中的文件用你的外部diff程序来比较。
Bbs.Svn8.Com
有时候查看整个旧版本的文件,比只看它和另一个修订版的不同更方便。 Svn中文网
svn listsvn list命令给你看在一个资料库目录中有什么文件,而不用把这些文件下载到你的本地机器上。 Svn中文网
$ svn list http://svn.collab.net/repos/svn
README
branches/
clients/
tags/
trunk/
Www.Svn8.Com 如果你想要一个更详细的列表,用--verbose (-v)选项可以得到这样的输出:
Bbs.Svn8.Com
$ svn list --verbose http://svn.collab.net/repos/svn
2755 harry 1331 Jul 28 02:07 README
2773 sally Jul 29 15:07 branches/
2769 sally Jul 29 12:07 clients/
2698 harry Jul 24 18:07 tags/
2785 sally Jul 29 19:07 trunk/
Bbs.Svn8.Com 这些列告诉你文件和目录上次被修改的修订版,谁修改了它,如果是文件会给出大小,上次修改日期,和它的名字。
Svn8.Com
关于历史的最后一点说明除了上面所有的命令,你可以使用带--revision选项的svn update和svn checkout来使整个工作副本“回到过去”。 [5]:
$ svn checkout --revision 1729 # Checks out a new working copy at r1729
…
$ svn update --revision 1729 # Updates an existing working copy to r1729
…
Www.Svn8.Com
--------------------------------------------------------------------------------
[5] 看,我们告诉过你Subversion是一个时间机器。
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/19.html
=========
其他有用的命令
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/20.html
虽然不像本章先前讨论过的那些命令那么常用,但是有时你也需要这些命令。 Bbs.Svn8.Com
svn cleanup当Subversion修改你的工作副本时(或者任何在.svn中的信息),它尝试尽可能做到安全。在改变一个工作副本前,Subversion把它的意图写到一个日志文件中。接下来它执行日志文件中的命令来应用要求的修改。最后,Subversion删除日志文件。从架构上来说,这与一个日志文件系统(journaled filesystem)类似。如果一个 Subversion操作被打断(例如,进程被杀掉了,或机器当掉了)了,日志文件仍在硬盘上。重新执行日志文件,Subversion可以完成先前开始的操作,这样你的工作副本能回到一个可靠的状态。
以下是svn cleanup所做的:它搜索你的工作副本并执行所有遗留的日志,在这过程中删除锁。如果Subversion曾告诉你你的工作副本的一部分被“锁定”了,那么你应该执行这个命令。另外, svn status会在锁定的项前显示L。 Svn8.Com
$ svn status
L somedir
M somedir/foo.c
$ svn cleanup
$ svn status
M somedir/foo.c
Svn中文网 svn import使用svn import是把未版本化的文件树复制到资料库的快速办法,它需要创建一个临时目录。
参考资料:www.svn8.com
$ svnadmin create /usr/local/svn/newrepos
$ svn import mytree file:///usr/local/svn/newrepos/some/project
Adding mytree/foo.c
Adding mytree/bar.c
Adding mytree/subdir
Adding mytree/subdir/quux.h
Committed revision 1.
参考资料:www.svn8.com 上面的例子把在some/project目录下mytree目录的内容复制到资料库中。
Svn中文网
$ svn list file:///usr/local/svn/newrepos/some/project
bar.c
foo.c
subdir/
参考资料:www.svn8.com 注意在导入完成后,原来的树没有被转化成一个工作副本。为了开始工作,你仍然需要svn checkout这个树的一个新的工作副本。 参考资料:www.svn8.com
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/20.html
=======
总结
现在,我们已经谈及了绝大部分的Subversion客户端命令。值得注意的是没包括那些处理分支、合并以及属性的命令。然而,你可能要花点时间来浏览一下???以得到Subversion全部那么多个命令的概念——以及如何用它们来完成你的工作。 参考资料:www.svn8.com
本文来自Svn中文网[www.svn8.com]转发请保留本站地址:http://www.svn8.com/svnsy/20080202/21.html