对于开发人员来说,subversion的使用无非就是对subversion的命令行的使用,只要学会了subversion命令行,subversion就会成为我们身上的一把刀!
为了能更清晰地说明subversion命令行的使用,现在我们假设这样的一个场景:
- subversion是安装在ubuntu系统上。
- subversion的版本库的目录位置为/home/test/svn/repository/myproject,svn协议的地址为svn://localhost/myproject
- 版本库的认证信息:username=abc password=abc
下面根据上面的场景来介绍svn的各个子命令。
svn import
svn import [PATH] URL
描述:
把Path内容导入到URL指向的版本库目录。这里的PATH可以是一个目录,也可以是某个文件。
实例:
首先手工创建如下的目录结构~/svn/sample/trunk、~/svn/sample/branches、~/svn/sample/tags
test@test-desktop:~$mkdir -p ~/svn/sample/trunk ~/svn/sample/branches ~/svn/sample/tags接着便可以导入到版本库了test@test-desktop:~$ svn import sample/ svn://localhost/myproject -m "first import" --username abc --password abc Adding sample/trunk Adding sample/branches Adding sample/tags Committed revision 1.Notice:-m、--username、--password是svn命令行的一些选项参数,这些选项参数会在后面介绍svn命令行时会有详细的说明。
svn checkout(co)
语法:
svn checkout URL[@REV]... [PATH]
描述:
从版本库中检出一份工作拷贝。如果没有提供PATH,则会检出以URL指向的目录作为目标目录,否则使用PATH作为目录。另外,URL指向的目录或PATH目录都不受版本控制。
实例:
下面我们分别把myproject版本库检出到工作拷贝目录~/svn/rain和目录~/svn/sally
test@test-desktop:~$ svn co svn://localhost/myproject ~/rain A /home/test/rain/trunk A /home/test/rain/branches A /home/test/rain/tags Checked out revision 1.还可以检出指定修定版本号的版本test@test-desktop:~$ svn co svn://localhost/myproject@HEAD ~/sally A /home/test/sally/trunk A /home/test/sally/branches A /home/test/sally/tags Checked out revision 3.Notic:checkout命令并不局限于检出版本库的根目录,你可以根据需要检出版本库下的任何子目录。
svn add
语法:svn add PATH...
描述:
把PATH指定的文件或目录添加到版本控制中来。执行这个命令并不会把PATH提交到版本库,只有在调用svn commit命令才会提交到版本库。此时的PATH可以使用通配符*
选项:
--depth:可选值有(empty——深度为PATH,files——深度为PATH与PATH的下一级子目录,immediates——深度为PATH与PATH的下一级子目录,infinity——深度为PATH下的所有子目录
--force:当PATH有某个子目录已经受到版本控制了,那么默认情况下,该目录下的文件不会受svn add命令的影响。如果添加--force选项,那么受到版本控制的目录下的文件就会受svn add命令影响了。
实例:
下面我们在工作拷贝rain中添加文本文件~/rain/trunk/rainDirectory/rainFile,rainFile的文本内容为"rainFile"。
#因为trunk目录已受版本控制了,默认地不会受版本控制目录下的文件及目录 test@test-desktop:~/rain$ svn add * svn: warning: 'branches' is already under version control svn: warning: 'tags' is already under version control svn: warning: 'trunk' is already under version control #添加--force参数可以强制添加受版本控制目录下的文件 test@test-desktop:~/rain$ svn add * --force A trunk/rainDirectory A trunk/rainDirectory/rainFile接着我们在工作拷贝sally中添加文本文件~/sally/trunk/sallyDirectory/sallyFile,sallyFile的文本内容为"sallyFile"。#如果PATH为目录,默认地,它会添加该目录及其子目录、子文件到版本控制中。 test@test-desktop:~/sally$ svn add trunk/sallyDirectory/ A trunk/sallyDirectory A trunk/sallyDirectory/sallyFile
svn commit(ci)
svn commit [PATH...]
描述:
提交文件到版本库。如果没有指定PATH,PATH默认为当前目录。它可以提交指定PATH下的子目录、子文件到版本库。
选项:
--message(-m) ARG:指定日志信息。Notice:只要是对版本库进行修动的操作命令都必须传送日志信息。
--file(-F) ARG:与--message类似,只是日志信息由一个文件来提供
--force-log:如果--file指定的文本文件是受版本控制的话,就要使用该参数。
实例:
下面我们分别把rain和sally工作拷贝添加的文件提交到版本库中
test@test-desktop:~/rain$ svn commit -m "commit a new file:trunk/rainDirectory/rainFile" Adding trunk/rainDirectory Adding trunk/rainDirectory/rainFile Transmitting file data . Committed revision 4.接着提交sally工作拷贝的文件test@test-desktop:~/sally$ svn ci trunk/sallyDirectory/ --message "commit a new file:trunk/rainDirectory/rainFile" Adding trunk/sallyDirectory Adding trunk/sallyDirectory/sallyFile Transmitting file data . Committed revision 5.
svn log
语法:
svn log PATH
svn log URL[@REV] [PATH...]
描述:
查看日志信息。
实例:
查看trunk/rainDirectory/rainFile的日志信息
test@tim-desktop:~/rain$ svn log trunk/rainDirectory/rainFile ------------------------------------------------------------------------ r4 | abc | 2012-05-01 11:12:33 +0800 (Tue, 01 May 2012) | 1 line commit a new file:trunk/rainDirectory/rainFile ------------------------------------------------------------------------
svn copy(cp)
语法:
svn copy SRC[@REC]... DST
描述:
文件的复制操作。该操作其实很像我们平时用的文件系统复制,只是在subversion中,复制操作是基于版本控制的,所以复制的速度和性能都很快。SRC和DST可以是工作拷贝(WC)路径或版本库路径(URL)。当指定了多个SRC,那么DST必须是一个目录地址。Notic:copy命令也可以用来创建分支。
选项:
--parents:如果路径上没有相应的目录,则创建该目录
实例:
下面我们把rain WC中的rainFile复制到~/rain/trunk/rainTempDirectory/readyDelFile、~/rain/trunk/rainTempDirectory/catFile并提交到版本库
test@test-desktop:~/rain$ svn copy trunk/rainDirectory/rainFile@HEAD trunk/rainTempDirectory/readyDelFile --parents A /home/test/rain/trunk/rainTempDirectory A trunk/rainTempDirectory/readyDelFile test@test-desktop:~/rain$ svn copy trunk/rainDirectory/rainFile@BASE trunk/rainTempDirectory/catFile A trunk/rainTempDirectory/catFile test@test-desktop:~/rain$ svn ci -m "commit files copy from trunk/rainDirectory/rainFile to trunk/rainTempDirectory/readDelFile & trunk/rainTempDirectory/catFile" Adding trunk/rainTempDirectory Adding trunk/rainTempDirectory/catFile Adding trunk/rainTempDirectory/readyDelFile Committed revision 6.接着按同样的方法把sally WC中的sallyFile复制到~/sally/trunk/sallyTempDirectory/readyDelFile、~/sally/trunk/sallyTempDirectory/catFile并提交到版本库
命令略接下来我们为我们的版本库创建两个分支——rain_branch-1.0和sally_branch-1.0
#创建分支rain_branch-1.0 test@test-desktop:~/rain$ svn cp svn://localhost/myproject/trunk@HEAD svn://localhost/myproject/branches/rain_branch-1.0 -m "create a branch for rain,version is 1.0" Committed revision 10. #创建分支sally_branch-1.0 test@test-desktop:~/sally$ svn cp svn://localhost/myproject/trunk@HEAD svn://localhost/myproject/branches/sally_branch-1.0 -m "create a branch for sally,version is 1.0" Committed revision 11.可能现在我们需要发布一个稳定的版本了——myproject1.0test@test-desktop:~/rain$ svn cp svn://localhost/myproject/trunk@HEAD svn://localhost/myproject/tags/myproject1.0 -m "myproject's first stable version 1.0" Committed revision 12.
svn list(ls)
语法:
svn list [TARGET[@REV]...]
描述:
查看TARGET的目录结构。TARGET可以是工作拷贝目录,也可以是URL指定的版本库目录。
选项:
--verbose(-v):显示一些额外信息
--xml:以xml格式打印输出
--recursive:显示TARGET及其子目录、子文件。效果与--depth infinity一样。
实例:
查看版本库中myproject/branches中的目录结构,可以看到我们的确已经在版本库中建立了两个分支rain_branch-1.0和sally_branch-1.0
test@test-desktop:~/rain$ svn ls svn://localhost/myproject/branches --depth infinity rain_branch-1.0/ rain_branch-1.0/rainDirectory/ rain_branch-1.0/rainDirectory/rainFile rain_branch-1.0/rainTempDirectory/ rain_branch-1.0/rainTempDirectory/catFile rain_branch-1.0/rainTempDirectory/readyDelFile rain_branch-1.0/sallyDirectory/ rain_branch-1.0/sallyDirectory/sallyFile rain_branch-1.0/sallyTempDirectory/ rain_branch-1.0/sallyTempDirectory/catFile rain_branch-1.0/sallyTempDirectory/readyDelFile sally_branch-1.0/ sally_branch-1.0/rainDirectory/ sally_branch-1.0/rainDirectory/rainFile sally_branch-1.0/rainTempDirectory/ sally_branch-1.0/rainTempDirectory/catFile sally_branch-1.0/rainTempDirectory/readyDelFile sally_branch-1.0/sallyDirectory/ sally_branch-1.0/sallyDirectory/sallyFile sally_branch-1.0/sallyTempDirectory/ sally_branch-1.0/sallyTempDirectory/catFile sally_branch-1.0/sallyTempDirectory/readyDelFile
svn cat
svn cat TARGET[@REV]...
描述:
查看TARGET指向的文件的内容。TARGET可以是指向工作拷贝的文件,也可以指向版本库的文件。如果TARGET指向工作拷贝文件,那么默认会显示该文件的BASE版本,非WORKING版本。
实例:
修改~/rain/trunk/rainDirectory/rainFile文件的内容为"modified rainFile",然后执行如下命令
#可以看到依然显示rainFile而不是modified rainFile test@test-desktop:~/rain$ svn cat trunk/rainDirectory/rainFile rainFile
svn blame(praise,annotate,ann)
语法:
svn blame TARGET[@REV]...
描述:
查看TARGET指向的文件每个版本的作者和版本信息。
实例:
查看rain工作拷贝trunk/rainDirectory/rainFile文件的作者和版本信息
test@test-desktop:~/rain$ svn blame trunk/rainDirectory/rainFile 4 abc rainFile
svn revert
svn revert PATH...
描述:
可以回滚工作拷贝中没有提交到版本库的所有修改,具体回滚哪些文件,这就由PATH来指定了。这里的PATH可以使用通配符*
实例:
回滚上次对trunk/rainDirectory/rainFile文件的修改
test@test-desktop:~/rain$ svn revert * --recursive Reverted 'trunk/rainDirectory/rainFile'
svn update(up)
语法:
描述:svn update [PATH...]
把工作拷贝更新最新版本
实例:
分别更新rain和sally的工作拷贝,可以看到,这里的更新会连带branches和tags都更新下来了。如果不希望某个用户不能更新某些路径下的内容,可以查看Subversion的权限控制
test@test-desktop:~/rain$ svn update A trunk/sallyTempDirectory A trunk/sallyTempDirectory/catFile A trunk/sallyTempDirectory/readyDelFile A trunk/sallyDirectory A trunk/sallyDirectory/sallyFile A branches/rain_branch-1.0 A branches/rain_branch-1.0/sallyTempDirectory A branches/rain_branch-1.0/sallyTempDirectory/catFile A branches/rain_branch-1.0/sallyTempDirectory/readyDelFile A branches/rain_branch-1.0/rainTempDirectory A branches/rain_branch-1.0/rainTempDirectory/catFile A branches/rain_branch-1.0/rainTempDirectory/readyDelFile A branches/rain_branch-1.0/sallyDirectory A branches/rain_branch-1.0/sallyDirectory/sallyFile A branches/rain_branch-1.0/rainDirectory A branches/rain_branch-1.0/rainDirectory/rainFile A branches/sally_branch-1.0 A branches/sally_branch-1.0/sallyTempDirectory A branches/sally_branch-1.0/sallyTempDirectory/catFile A branches/sally_branch-1.0/sallyTempDirectory/readyDelFile A branches/sally_branch-1.0/rainTempDirectory A branches/sally_branch-1.0/rainTempDirectory/catFile A branches/sally_branch-1.0/rainTempDirectory/readyDelFile A branches/sally_branch-1.0/sallyDirectory A branches/sally_branch-1.0/sallyDirectory/sallyFile A branches/sally_branch-1.0/rainDirectory A branches/sally_branch-1.0/rainDirectory/rainFile A tags/myproject1.0 A tags/myproject1.0/sallyTempDirectory A tags/myproject1.0/sallyTempDirectory/catFile A tags/myproject1.0/sallyTempDirectory/readyDelFile A tags/myproject1.0/rainTempDirectory A tags/myproject1.0/rainTempDirectory/catFile A tags/myproject1.0/rainTempDirectory/readyDelFile A tags/myproject1.0/sallyDirectory A tags/myproject1.0/sallyDirectory/sallyFile A tags/myproject1.0/rainDirectory A tags/myproject1.0/rainDirectory/rainFile Updated to revision 12.更新操作并不是每次都那么顺利,因为有时会出现“冲突”的状态。下面我们创建一个”冲突“的场景。
rain修改了trunk/rainDirectory/rainFile为“rain modify rainFile"并且提交(略)
另一方面,sally也修改了trunk/rainDirectory/rainFile为"sally modify rainFile"。
接着sally执行更新操作:
test@tim-desktop:~/sally$ svn update Conflict discovered in 'trunk/rainDirectory/rainFile'. Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: s (e) edit - 打开文本编辑器,手工解决冲突问题 (df) diff-full - 显示所有冲突的详细内容 (r) resolved - accept merged version of file (dc) display-conflict - 显示所有冲突 (忽略合并版本) (mc) mine-conflict - 在冲突的位置使用我自己的版本 (tc) theirs-conflict - 在冲突的位置使用版本库中的版本 (mf) mine-full - 整个冲突文件都使用我自己的版本 (tf) theirs-full - 整个冲突文件都使用版本库的版本 (p) postpone - 现在先不处理冲突,稍后手工解决冲突 (l) launch - 启动其他工具来解决冲突 (s) show all - show this list
svn resolve
语法:
svn resolve PATH... --accept ARG
描述:
解决工作拷贝中处于“冲突”状态的文件
选项:
--accept:该参数指示着如何去解决冲突。它有以下的可选值:
base:使用该文件修改前的版本。
working:使用该文件修改后的版本。
mine-full:所有的冲突文件都使用我自己的版本,就像没有进行update操作一样。
theirs-full:所有的冲突文件都使用版本库的版本,忽略所有我做的修改。
mine-conflict:在冲突的位置使用我自己的版本。
theirs-conflict:在冲突的位置使用版本库的版本。
实例:
在上面的冲突场景中,我们选择postpone。那么,sally就可以使用resolve命令来解决冲突了。
test@test-desktop:~/sally$ svn resolve trunk/rainDirectory/rainFile --accept theirs-full Resolved conflicted state of 'trunk/rainDirectory/rainFile'查看解决冲突后文件的内容
test@test-desktop:~/sally$ svn cat trunk/rainDirectory/rainFile rain modify rainFile
svn delete(del,remove,rm)
语法:svn delete PATH...
svn delete URL...
描述:
删除PATH\URL指向的文件。如果是PATH方式,并不会马上提交到版本库,但在工作拷贝中会删除PATH指向的文件,如果想在工作拷贝中保留该文件,可以添加--keep-local参数。该命令默认下不会删除任何修改过的文件或不受版本控制的文件,如果想要强制执行这些操作,可以添加--force参数
如果是URL方式是自动提交到版本库。
实例:
分别通过PATH方式、URL方式删除readyDelFile
test@test-desktop:~/rain$ svn delete trunk/rainTempDirectory/readyDelFile D trunk/rainTempDirectory/readyDelFile test@test-desktop:~/rain$ svn commit -m "delete rain's readyDelFile" Deleting trunk/rainTempDirectory/readyDelFile Committed revision 14.test@tim-desktop:~/sally$ svn rm svn://localhost/myproject/trunk/sallyTempDirectory/readyDelFile -m "delete sally's readyDelFile" Committed revision 15.
svn diff
语法:
diff [-c M | -r N[:M]] [TARGET...]
diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]]
diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]
描述:
显示两个版本或两个PATH指定的文件的差异。diff的用途:
- 显示文件修改前和修改后的差异。
- TARGET的默认为当前目录。如果TARGET指向工作拷贝目录,N默认是base版本,M默认是working版本。如果TARGET是URL,那么必须给定N的值,M的值默认为HEAD。-r N:M的意思对比N和M版本。-c M参数等效于-r M-1:M
- 显示OLD-TGT与NEW-TGT的差别。OLD_TGT和NEW_TGT可以是工作拷贝,也可以是版本库URL。如果NEW-TGT没有指定,默认为OLD-TGT。-r N:M分别提供给OLD_TGT和NEW_TGT版本号。
svn diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]是svn diff --old=OLD-URL[@OLDREV] --new=NEW-URL[@NEWREV]的缩写版本。svn diff -r N:M URL是svn diff -r N:M --old=URL --new=URL的缩写版本。如果TARGET是URL,那么即可以通过-r N:M方式提供版本号,也可以通过@方式。如果TARGET是工作拷贝目录,那么如果没有提供--reversion(-r)参数时,默认N为base版本,M为working版本。如果只指定了-r N,那么M为working版本。
实例:
修改trunk/rainDirectory/rainFile为"rain modify rainFile is diff",执行下面命令
test@tim-desktop:~/sally$ svn diff Index: trunk/rainDirectory/rainFile =================================================================== --- trunk/rainDirectory/rainFile (revision 13) +++ trunk/rainDirectory/rainFile (working copy) @@ -1 +1 @@ -rain modify rainFile +rain modify rainFile is difftest@tim-desktop:~/sally$ svn diff --old=svn://localhost/myproject/branches/rain_branch-1.0/rainDirectory/rainFile --new=svn://localhost/myproject/trunk/rainDirectory/rainFile@HEAD Index: rainFile =================================================================== --- rainFile (.../branches/rain_branch-1.0/rainDirectory/rainFile) (revision 15) +++ rainFile (.../trunk/rainDirectory/rainFile) (revision 15) @@ -1 +1 @@ -rainFile +rain modify rainFile
svn merge
svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]
描述:
对比两个SOURCE,把两者的差异合并到TARGET_WCPATH。如果省略TARGET_WCPATH,默认为当前目录,TARGET_WCPATH必须是受版本控制的。
SOURCE可以是工作拷贝路径(它会自动对应版本库的路径),也可以是URL指定的版本库路径
两个不同的SOURCE可以是两个具有相同路径不同版本的SOURCE,也可以是不同路径相同版本的SOURCE,当然也可以是即不同路径也不同版本的SOURCE。
关于merge命令有一个比较迷惑人的地方是————它是如何定义两个SOURCE的差异呢?
- 对于语法一,-r N:M的方式。假如M版本比N版本多了一个文件a.txt,即由N变成M需要添加a.txt文件(add操作),所以实际的merge命令会在TARGET_WCPATH上添加一个文件a.txt。(-c参数同理)如果变成-r M:N,那么实际的merge命令就会变成是在TARGET_WCPATH上删除a.txt。
- 对于语法二,假如SOURCE1@N比SOURCE2@M少了一个文件a.txt,即由SOURCE1@N变成SOURCE2@M需要添加一个a.txt文件(add操作),所以实际的merge命令是在TARGET_WCPATH上添加a.txt文件。如果SOURCE1@N与SOURCE2@M的位置对调,那么实际的merge命令就会变成是在TARGET_WCPATH上删除a.txt文件
一句话总结merge的机制就是:把版本N(SOURCE1@N)变化成版本M(SOURCE2@M)所需的操作应用到TARGET_WCPATH中。语法三中的SOURCE只能是URL指定的版本库目录,它的作用是把直接把SOURCE复制到TARGET_WCPATH。
svn status(stat,st)
svn status [PATH...]
描述:
查看工作空间的的文件状态。
svn propdel/propedit/propget/propset/proplist
svn prop* PROPNAME [PATH...]
svn prop* PROPNAME --revprop -r REV [TARGET]描述:
这五个命令都是对svn的属性进行操作的,因此就放在一些说明了。语法一是作用于本地工作拷贝,而语法二则是作用于远程仓库的某个指定的版本。
实例:
如要忽略com目录下的sin90lzc目录,使其不受版本控制。
$ svn propset svn:ignore "sin90lzc" com