一、版本库访问URL
模式 访问方法
file:/// 直接版本库访问(本地磁盘)。
http:// 通过配置Subversion的Apache服务器的WebDAV协议。
https:// 与http://相似,但是包括SSL加密。
svn:// 通过svnserve服务自定义的协议。
svn+ssh:// 与svn://相似,但通过SSH封装。
二、修订版本关键字
HEAD
版本库中最新的版本。
BASE
工作拷贝中的“原始”修订版本。
COMMITTED
在BASE版本之前(或在Base)一个项目最后修改的版本。
PREV
一个项目最后修改版本之前的那个版本(技术上为COMMITTED -1)。
PREV、BASE、和COMMITTED指的都是本地路径而不是URL
三、修订版本日期
在任何你使用特定版本号和版本关键字的地方,你也可以在“{}”中使用日期,你也可通过日期或者版本号配合使用来访问一段时间的修改!
如下是一些Subversion能够接受的日期格式,注意在日期中有空格时需要使用引号。
$ 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}
当你指定一个日期,Subversion会在版本库找到接近这个日期的最新版本
你可以使用时间段,Subversion会找到这段时间的所有版本
$ svn log --revision {2002-11-20}:{2002-11-29}
我们也曾经指出,你可以混合日期和修订版本号
$ svn log --revision {2002-11-20}:4040
四、初始化的checkout
大多数时候,你会使用checkout从版本库取出一个新拷贝开始使用Subversion,这样会在本机创建一个项目的本地拷贝,这个拷贝包括版本库中的HEAD(最新的)版本
$ svn checkout http://svn.collab.net/repos/svn/trunk
通过输入特定URL取出任意深度的子目录
$ svn checkout http://svn.collab.net/repos/svn/trunk/doc/book/tools
在版本库URL之后指定一个目录,这样会将你的工作目录放到你的新目录,举个例子:
$ svn checkout http://svn.collab.net/repos/svn/trunk subv
这样将把你的工作拷贝放到subv而不是和前面那样放到trunk
五、svn status可能返回的状态码
L abc.c # svn已经在.svn目录锁定了abc.c
M bar.c # bar.c的内容已经在本地修改过了
M baz.c # baz.c属性有修改,但没有内容修改
X 3rd_party # 这个目录是外部定义的一部分
foo.o # svn并没有管理foo.o
! some_dir # svn管理这个,但它可能丢失或者不完整
~ qux # 作为file/dir/link进行了版本控制,但类型已经改变
I .screenrc # svn不管理这个,配置确定要忽略它
A + moved_dir # 包含历史的添加,历史记录了它的来历
M + moved_dir/README # 包含历史的添加,并有了本地修改
D stuff/fish.c # 这个文件预定要删除
A stuff/loot/bloo.h # 这个文件预定要添加
C stuff/loot/lump.c # 这个文件在更新时发生冲突
R xyz.c # 这个文件预定要被替换
S stuff/squawk # 这个文件已经跳转到了分支
svn status也有一个--verbose(-v)选项,它可以显示工作拷贝中的所有项目,即使没有改变过
$ svn status --verbose
上面所有的svn status调用并没有联系版本库,只是与.svn中的元数据进行比较的结果,最后,是--show-updates(-u)参数,它将会联系版本库为已经过时的数据添加新信息:
$ 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
这三个命令(svn status、svn diff和 svn revert)都可以在没有网络的情况下工作
六、解决冲突
我们可以使用svn status -u来预测冲突
$ svn update
U INSTALL
G README
C bar.c
Updated to revision 46
C表示冲突,说明服务器上的改动同你的改动冲突了,你需要自己手工去解决
如果你遇到冲突,三件事你可以选择:
1,“手动”合并冲突文本(检查和修改文件中的冲突标志)。
小于号、等于号和大于号串是冲突标记,并不是冲突的数据,你一定要确定这些内容在下次提交之前得到删除,前两组标志中间的内容是你在冲突区所做的修改
修改完毕,并去掉表示的符号
$ svn resolved sandwich.txt
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
2,用某一个临时文件覆盖你的工作文件。
$ cp sandwich.txt.r2 sandwich.txt
$ svn resolved sandwich.txt
3,运行svn revert <filename>来放弃所有的修改。
七、提交修改
svn commit命令发送所有的修改到版本库,当你提交修改时,你需要提供一些描述修改的日志信息,你的信息会附到这个修订版本上,如果信息很简短,你可以在命令行中使用--message(-m)选项
$ svn commit --message "Corrected number of cheese slices."
Sending sandwich.txt
Transmitting file data .
Committed revision 3.
如果你把写日志信息当作工作的一部分,你也许会希望通过告诉Subversion一个文件名得到日志信息,使用--file选项:
$ svn commit --file logmsg
Sending sandwich.txt
Transmitting file data .
Committed revision 4.
八、检验历史
svn log 展示给你主要信息:附加在版本上的日志信息和所有版本的路径修改。
svn diff
1,检查本地修改
不使用任何参数调用时,svn diff将会比较你的工作文件与缓存在.svn的“原始”拷贝
2,比较工作拷贝与版本库
如果传递一个--revision(-r)参数,你的工作拷贝会与指定的版本比较。
$ svn diff --revision 3 rules.txt
3,比较版本库和版本库
如果通过--revision (-r)传递两个版本号,通过冒号分开,这两个版本会进行比较
$ svn diff --revision 2:3 rules.txt
你不仅可以用svn diff比较你工作拷贝中的文件,你甚至可以通过提供一个URL参数来比较版本库中两个文件的的区别,通常在本地机器没有工作拷贝时非常有用
svn cat 如果你只是希望检查一个过去的版本而不希望察看它们的区别,使用svn cat
svn list可以在不下载文件到本地目录的情况下来察看目录中的文件
$ svn list http://svn.collab.net/repos/svn
如果你希望察看详细信息,你可以使用--verbose (-v)参数
$ svn list --verbose http://svn.collab.net/repos/svn
九、其他命令
svn cleanup 查找工作拷贝中的所有遗留的日志文件,删除进程中的锁
svn import命令是拷贝用户的一个未被版本化的目录树到版本库最快的方法
$ 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.
将会拷贝目录mytree到版本库的some/project
$ svn list file:///usr/local/svn/newrepos/some/project
bar.c
foo.c
subdir/
===============================================================================================
分支与合并
一、建立分支
建立分支最简单的方法:svn copy可以直接对两个URL操作
$ svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Creating a private branch of /calc/trunk."
Committed revision 341.
二、拷贝特定的修改
查看区别
$ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk
svn merge命令几乎完全相同,但不是打印区别到你的终端,它会直接作为本地修改作用到你的本地拷贝
$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk
U integer.c
$ svn status
M integer.c
当你提交你的修改时,确定你的日志信息中说明你是从某一版本搬运了修改
$ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk."
svn merge这个命令包括三个参数:
1,初始的版本树(通常叫做比较的左边),
2,最终的版本树(通常叫做比较的右边),
3,一个接收区别的工作拷贝(通常叫做合并的目标)。
svn merge的语法允许非常灵活的指定参数
$ svn merge http://svn.example.com/repos/branch1@150 \
http://svn.example.com/repos/branch2@212 \
my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk
第一种语法使用URL@REV的形式直接列出了所有参数,
第二种语法可以用来作为比较同一个URL的不同版本的简略写法,
最后一种语法表示工作拷贝是可选的,如果省略,默认是当前目录。
三、预览合并
$ svn merge --dry-run -r 343:344 http://svn.example.com/repos/calc/trunk
U integer.c
$ svn status
# nothing printed, working copy is still unchanged.
--dry-run选项实际上并不修改本地拷贝,它只是显示实际合并时的状态信息,对于得到“整体”的印象,这个命令很有用,因为svn diff包括太多细节
四、常见用例
查找分支产生的版本(分支的“基准”)的最好方法是在svn log中使用--stop-on-copy选项,log子命令通常会显示所有关于分支的变化,包括 创建分支的过程,就好像你在主干上一样,--stop-on-copy会在svn log检测到目标拷贝或者改名时中止日志输出
$ svn log --verbose --stop-on-copy \
http://svn.example.com/repos/calc/branches/my-calc-branch
…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
A /calc/branches/my-calc-branch (from /calc/trunk:340)
$
如下是最终的合并过程,然后
$ cd calc/trunk
$ svn update
At revision 405.
$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U integer.c
U button.c
U Makefile
$ svn status
M integer.c
M button.c
M Makefile
# ...examine the diffs, compile, test, etc...
$ svn commit -m "Merged my-calc-branch changes r341:405 into the trunk."
Sending integer.c
Sending button.c
Sending Makefile
Transmitting file data ...
Committed revision 406.
五、取消修改
svn merge另一个常用的做法是取消已经做得提交
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U integer.c
$ svn status
M integer.c
$ svn diff
…
# verify that the change is removed
…
$ svn commit -m "Undoing change committed in r303."
Sending integer.c
Transmitting file data .
Committed revision 350.
六、找回删除的项目
一个好的策略是使用svn log --verbose来察看你删除的项目,--verbose选项显示所有改变的项目的每一个版本 ,你只需要找出你删除文件或目录的那一个版本
svn copy命令,精确的拷贝版本和路径“坐标对”到你的工作拷贝
$ svn copy --revision 807 \
http://svn.example.com/repos/calc/trunk/real.c ./real.c
$ svn status
A + real.c
$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding real.c
Transmitting file data .
Committed revision 1390.
七、发布分支
这是版本控制可以做的帮助,典型的过程如下:
开发者提交所有的新特性到主干。 每日的修改提交到/trunk:新特性,bug修正和其他。
这个主干被拷贝到“发布”分支。 当小组认为软件已经做好发布的准备(如,版本1.0)然后/trunk会被拷贝到/branches/1.0。
项目组继续并行工作,一个小组开始对分支进行严酷的测试,同时另一个小组在/trunk继续新的工作(如,准备2.0),如果一个bug在任何一个位置被发现,错误修正需要来回运送。然而这个过程有时候也会结束,例如分支已经为发布前的最终测试“停滞”了。
分支已经作了标签并且发布,当测试结束,/branches/1.0作为引用快照已经拷贝到/tags/1.0.0,这个标签被打包发布给客户。
分支多次维护。当继续在/trunk上为版本2.0工作,bug修正继续从/trunk运送到/branches/1.0,如果积累了足够的bug修正,管理部门决定发布1.0.1版本:拷贝/branches/1.0到/tags/1.0.1,标签被打包发布。
整个过程随着软件的成熟不断重复:当2.0完成,一个新的2.0分支被创建,测试、打标签和最终发布,经过许多年,版本库结束了许多版本发布,进入了“维护”模式,许多标签代表了最终的发布版本。
八、转换工作拷贝
svn switch命令改变存在的工作拷贝到另一个分支
$ svn info | grep URL
URL: http://svn.example.com/repos/calc/trunk
$ svn switch http://svn.example.com/repos/calc/branches/my-calc-branch
U integer.c
U button.c
U Makefile
Updated to revision 341.
$ svn info | grep URL
URL: http://svn.example.com/repos/calc/branches/my-calc-branch
九、版本库布局
如果一个版本库只是存放一个项目,人们会在顶级目录创建这些目录:
/trunk
/branches
/tags
如果一个版本库保存了多个项目,管理员会通过项目来布局
/paint/trunk
/paint/branches
/paint/tags
/calc/trunk
/calc/branches
/calc/tags
十、数据的生命周期
假定你最终完成了calc项目你的个人分支上的所有工作,在合并了你的所有修改到/calc/trunk后,没有必要继续保留你的私有分支目录
$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Removing obsolete branch of calc project."
Committed revision 375.
如果浏览你删除的目录还不足够,你可以把它找回来,恢复数据对Subversion来说很简单,如果你希望恢复一个已经删除的目录(或文件)到HEAD,仅需要使用svn copy -r来从旧的版本拷贝出来
$ svn copy -r 374 http://svn.example.com/repos/calc/branches/my-calc-branch \
http://svn.example.com/repos/calc/branches/my-calc-branch
Committed revision 376.