我打算一口气讲完SVN的使用,所以,在看之前呢,请先深深的吸一口气(怎么听着像黑龙公主),当然吸完后还是要呼出来的。不要憋着了。
我们可能希望一来就直接操作。列出一堆命令。详细的命令参数等信息,我们都可以加入 --help 选项获取,下面不会详细介绍。除非必要。现在先看下面的例子:
$svn --help
usage: svn <subcommand> [options] [args]
Subversion command-line client, version 1.6.12.
Type 'svn help <subcommand>' for help on a specific subcommand.
Type 'svn --version' to see the program version and RA modules
or 'svn --version --quiet' to see just the version number.
Most subcommands take file and/or directory arguments, recursing
on the directories. If no arguments are supplied to such a
command, it recurses on the current directory (inclusive) by default.
Available subcommands:
add
blame (praise, annotate, ann)
cat
changelist (cl)
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
lock
log
merge
mergeinfo
mkdir
move (mv, rename, ren)
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
resolve
resolved
revert
status (stat, st)
switch (sw)
unlock
update (up)
Subversion is a tool for version control.
For additional information, see http://subversion.tigris.org/
好了,什么都出来了。一大堆信息。慢慢读吧。可是这样的方式,对我们使用SVN并无指导意义。什么时候用什么命令? 下面就来说一下SVN的基本使用,在此之前,还有两个重要的东西需要理解。
SVN 除了可以让你追溯历史,还有一个重要的功能,便是多人协作。我们要解决的问题不仅仅是可以从历史中恢复。还有如果多人同时修改一个文件,那么该以谁的为主呢?
所以在SVN中,我们有两种使用模式:
Lock-Modify-Unlock
简单的说就是,给需要修改的文件加锁,然后修改,然后解锁。
这是一个很好的办法。但是如果一个文件被锁住了,那么其他人就不能修改了。而此时如果是我在修改文件头,而你需要修改文件末尾的话,你也只能等我修改完。这样是很浪费你的时间的。所以我们又有另外一种模式。
Copy-Modify-Merge
这是一种很高级的模式,从库中拷贝一份,修改,然后根据拷贝的和库中的不同,在合并。为什么说高级呢,因为合并是一个很复杂的过程。很可能失败。但是这种方法却尽可能使大家不受影响。例如你和我同时修改一个文件,我改文件头,你改文件尾,然后一提交,就给合成一份了。不会互相打扰。事实上问题比这复杂的多。
好了,说了这么多废话。我们可以正式开始了。
虽然一般情况,我们是不用自己去创建一个SVN库的,现在为了说明流畅,我们从创建一个库开始。
$svnadmin create /var/idp/repos
于是我们创建了一个SVN库。到下面看看
$ls /var/idp/repos
conf db format hooks locks README.txt
我们的库就创建好了。这里不多说, svnadmin是一个高级命令,我们基本用不到。
导入需要管理的文件:
$svn import /home/madic/code file:///var/idp/repos -m "init code"
Adding /home/madic/code/signo
Adding /home/madic/code/signo/sigset.c
Adding (bin) /home/madic/code/signo/wait
Adding /home/madic/code/signo/wait.c
Committed revision 1.
这里版本变为1,初始版本为0。 每次对库的操作改变,都会产生一个新的版本。版本是我们追溯历史的一个索引。在版本管理中非常重要。当前库中最新的版本可以用HEAD表示。HEAD版也就是库中最新版本。
我们把 /home/madic/code 文件下的文件目录都导入了svn库,从此,他们就被时光机管理,数据永不丢失(当然你干掉时光机,数据还是会丢失的)。
注意 (bin) 表示这是一个二进制文件,非文本文件。
除了import 外,我们还可以用 svn add 添加文件。
使用list命令查看库中文件
$svn list file:///var/idp/repos
signo/
signo/sigset.c
signo/wait
signo/wait.c
现在,我们开始工作了。那么,就使用 CMC(Copy-Modify-Merge)模式吧。
如何创建一个Working Copy 呢?看:
$svn checkout file:///var/idp/repos /home/madic/code_svn
A /home/madic/code_svn/signo
A /home/madic/code_svn/signo/sigset.c
A /home/madic/code_svn/signo/wait
A /home/madic/code_svn/signo/wait.c
Checked out revision 1.
恭喜我们现在拥有一个Working Copy了,你就在这个WorkingCopy中折腾吧,只要不提交,那么对库来说就没有任何影响。就算你用了 rm 不小心删除了某个文件,不用着急。使用update便可以找回。
$svn update
svn update
Restored 'main.c'
At revision 1.
这里,我们删掉 main.c 然后到WC 下,执行 svn update 命令,就找回main.c了。
在Working Copy 目录中,Subversion如何知道文件的情况呢,其实这些都是 .svn的功劳。每个SVN管理的WC中,都会有一个隐藏的文件夹,.svn
$ls -la .svn
drwxr-xr-x 6 madic madic 4096 2011-07-26 11:00 .svn
如果不小心误删除,也可以用svn update恢复。
接下来,我们开始正常的编辑文件。编辑之前,已定要使用svn update 来确保你编辑的文件是最新的。如果不是最新的,那么这个文件就是 Out-of-date了,此时你的编辑就不能被提交到库中。编辑时,你不必使用svn的命令了。你可以用任何编辑器编辑文件。当你编辑完成后保存。
$svn status -q
M readme.txt
这个M表示此文件被修改了。于是我们需要把她提交到库,这样别人才能看到我修改的东西。
$svn commit -m "我修改了文件内容" readme.txt
svn commit -m "modify" readme.txt
Sending readme.txt
Transmitting file data .
Committed revision 8.
文件被提交,版本更新到8.
这样,我们就完成了一个最基本的SVN操作流程。也许如果没有什么大事,我们就到此结束了。难道还有什么问题吗?
上面提到,我们在修改的同时,可能别人也在修改。所以要尽量在每次修改的时候,保持我们的WC和库中的是同步的,也就是最新的。我们使用svn update来使自己的working copy是最新的。我们也可以用一个新的命令来看WC的状态。
$svn status -u -v readme.txt
M 8 8 madic readme.txt
M * 8 3 madic foo.c
我们看到readme.txt 目前是M(modify)状态,说明此文件被改了。当前版本和最新版本都是8 ,用户是madic。
而foo.c 多了个星号,这表明foo.c 已经out-of-date 了。也就是说,我们在修改的版本,已经不是最新的了。在我们修改的时候,已经有人提交了新的版本。
除了 M表示修改,还有 U表示更新,D表示删除,A 表示新增, C表示冲突。
有时候有两个MM,此时并非表示美眉,而是文件的内容和属性都被改变了。
同样UU表示属性和内容都更新了。
所以,在我们提交以后,并非就结束了,此时,我们需要查看一下状态。如果有文件处于C状态,那么说明我们遇到麻烦了。因为C表示冲突了,一定是某个人和我们在改同一个地方。
这时,最好的办法是直接找到和我们冲突的修改人。然后沟通吧。是你死还是我亡。冲突实际上是在svn update的时候发生的。由于我编辑的太久了,你已经提交了一个新版本,我提交的时候,提示 out-of-date了,于是我svn update,冲突出现:
$ svn update
Conflict discovered in 'readme.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
(mc) mine-conflict, (tc) theirs-conflict,
(s) show all options:
这时几个选择出现了,postpone 的意思是暂时推后处理,我可能要和那个和我冲突的家伙商量一番。 diff-full,则是比比看,到底什么地方冲突了。edit,修改冲突合并的文件。 mc,这个霸道,直接用我的。 tc , 底气不足,还是用别人修改的吧。我们一切三思而后行,所以选择了p,然后在看看文件目录下有什么。
多了三个文件:
readme.txt.mine readme.txt.r9 readme.txt readme.txt.r8
我们来说说这三个文件:readme.txt.mine 后最 mine是本地最新的。
readme.txt.r9 很明显,是版本9的,这个版本正式库中最新的版本。
readme.txt.r8 这个版本是库中最新的版本的前一版本。
我们来看一下,现在的readme.txt
$cat readme.txt
<<<<<<< .mine
hi
=======
hello
>>>>>>> .r9
很明显,我的版本中是hi ,而r9 的是hello。
好吧,我明白了。现在假设我们很明白,或者已经和发生冲突的文件的编辑同事商量好了。我们就要解决冲突了。
首先,上面说的三个文件,如果存在,我们就提交不了。
其次,需要选择一个解决方法。
$svn resolve --accepting working reademe.txt
svn resolve 是解决冲突的命令。解决的方法由--accepting 选项决定。
base 恢复到冲突前的一个版本。
mine-full 恢复到以我的修改为主的版本
their-full 恢复到库中最新版本
working 手动解决
所以,上面的那句命令其实还有问题,因为我们还没有手工修改文件。
于是我们打开readme.txt,去掉哪些冲突标识
<<<<<<< .mine
hi
=======
hello
>>>>>>> .r9
修改为
No hi no hello
然后保存readme.txt
在使用
$svn resolve --accepting working reademe.txt
注意,这一步以后,并没有真正完成冲突解决。
$svn commit -m "conflict resole"
Sending readme.txt
Transmitting file data .
Committed revision 10.
这次提交OK。冲突至此解决。
有时候,我们编写到一半发现有人提交了更新或者是越写越乱,我们想放弃这次编辑,恢复到上一个版本,当然,我们可以直接rm掉,然后update,我们也可以这样:
$svn revert readme.txt
Reverted 'readme.txt'
问题解决以后,请使用svn status 查看一下状态,是否正常了。
$svn status -vu readme.txt
10 10 yinshaoxin readme.txt
Status against revision: 10
没有什么M,C,* ,D, ? 这些,说明状态正常。
对于我们操作的这些,我们可以通过历史svn log来查看状态。
$svn log
r9 | yinshaoxin | 2011-07-26 13:39:12 +0800 (Tue, 26 Jul 2011) | 1 line
shaoxin
------------------------------------------------------------------------
r8 | madic | 2011-07-26 11:12:47 +0800 (Tue, 26 Jul 2011) | 1 line
modify
------------------------------------------------------------------------
r7 | madic | 2011-07-26 09:35:51 +0800 (Tue, 26 Jul 2011) | 1 line
code
------------------------------------------------------------------------
r6 | madic | 2011-07-20 15:43:52 +0800 (Wed, 20 Jul 2011) | 1 line
pa
------------------------------------------------------------------------
r5 | madic | 2011-07-20 15:42:19 +0800 (Wed, 20 Jul 2011) | 1 line
p
------------------------------------------------------------------------
r4 | madic | 2011-07-20 10:40:03 +0800 (Wed, 20 Jul 2011) | 1 line
dir
------------------------------------------------------------------------
r3 | madic | 2011-07-19 14:01:49 +0800 (Tue, 19 Jul 2011) | 1 line
keywords
------------------------------------------------------------------------
r2 | madic | 2011-07-19 13:58:24 +0800 (Tue, 19 Jul 2011) | 1 line
new test
------------------------------------------------------------------------
r1 | madic | 2011-07-15 16:56:05 +0800 (Fri, 15 Jul 2011) | 1 line
ci chage
------------------------------------------------------------------------
天哪,所有的svn日志都显示出来了。我们可以使用r来确定一个范围。
这就是时光机的历史查看了。来吧,想看哪一个版本的。
$svn log -r 5:9
------------------------------------------------------------------------
r5 | madic | 2011-07-20 15:42:19 +0800 (Wed, 20 Jul 2011) | 1 line
p
------------------------------------------------------------------------
r6 | madic | 2011-07-20 15:43:52 +0800 (Wed, 20 Jul 2011) | 1 line
pa
------------------------------------------------------------------------
r7 | madic | 2011-07-26 09:35:51 +0800 (Tue, 26 Jul 2011) | 1 line
code
------------------------------------------------------------------------
r8 | madic | 2011-07-26 11:12:47 +0800 (Tue, 26 Jul 2011) | 1 line
modify
------------------------------------------------------------------------
r9 | yinshaoxin | 2011-07-26 13:39:12 +0800 (Tue, 26 Jul 2011) | 1 line
shaoxin
------------------------------------------------------------------------
注意 -r 5:9 和 -r 9:5 是不同的顺序显示。
当然也可以指定一个文件的版本日志。
使用log注意,当你提交一个版本后,log并看不到这个日志。
因为 commit 和 update是独立的。commit并不更新本地版本。我们只有使用 update以后,在使用log则可以看到。
还有,如果你使用svn log 不指定路径的话,那么默认的是当前的目录。这样,对于其他目录的log,我们只有一条空日志。
$-------------------------------------------
最后不要像我一样,日志都是乱七八糟,请重视日志,因为在以后查找问题梳理版本变化的时候,会对你有很大帮助。
好了,从现在开始,你已经基本掌握SVN的用法了。如果具体命令参数不会用,请使用 help 。
如果你想了解的更多一点,那么我们继续看下一章。