分支与合并
一般来说一个SVN项目的路径为
ProjectName
Trunk
Branches
一般来说Trunk放的是工作的主目录,而branches放的是分支
$ 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.
这是从client创建branch的copy,但是很慢,不要这么做,还是在server上直接copy
Cheap Copy
在server的repository中的svn copy是一种cheap copy,指的是时间少,不占空间,因为SVN的copy往往是建立一种hard link而不是复制黏贴file
分支历史
使用svn log -v integer.c命令查看分支文件的历史时,可以看到之前在trunk目录下时的历史,包括创建分支的步骤
changeset
在SVN中的定义,认为changeset是指一次commit所产生的修改的list,每次commit会产生一个新的revision ID,这个ID N与N-1之间的区别就是一个changeset,SVN在merge的时候可以通过传递revision ID来merge(-c 9238)这时候就会把9238这个changeset merge到你的branch中
把/trunk目录下的更新,merge到branch中
命令格式svn merge URL
$ pwd
/home/user/my-calc-branch
$ svn merge ^/trunk
--- Merging r345 through r356 into '.':
U button.c
U integer.c
这里成功的前提是,没有conflict
同时通配符^是在1.6时引入的
将branch content修改提交到trunk中
1.svn update
2.svn merge--reintegrate^/trunk #将主目录的更新merge到branch
3.测试
4.简单使用svn commit –m “comments”命令
reintegrate选项,用来标记trunk的lastest version与branch中的lastest version的差别,也就是你的branch到底修改了哪些,用来在commit的时候起作用
删除branch
在merge――reintegrate之后,可以删除当前的branch,如果以后需要,可以通过svn log整个/branch目录来查看历史,找到删除的branch,恢复
继续在branch上工作
在1.5SVN中,一旦进行了merge - -reintegrate之后,branch就不可用了,因为branch不能在从trunk获得更新,所以最好的办法就是删除,然后重新创建一个branch
$ svndeletehttp://svn.example.com/repos/calc/branches/my-calc-branch -m "Remove my-calc-branch."
Committed revision 392.
$svncopy
http://svn.example.com/repos/calc/trunkhttp://svn.example.com/repos/calc/branches/new-branch-m "Create a new branch from trunk."
Committed revision 393.
$ cd my-calc-branch
$ svnswitch^/branches/new-branch
Updated to revision 393.
注意最后的svn switch命令
合并信息预览
可以在运行svn merge之前,预览所要merge的信息,包括revision ID等,关于所有的merge信息,会被SVN存放在svn:mergeinfo这个property中,运行
svnmergeinfo^/trunk TARGET
命令可以看到要进行merge的revision ID,同时TARGET表示merge到的目录,可以省略,省略之后就是当前目录
同时可以使用- -dry-run选项,来提前查看要merge的文件的状态,简单说就是进行了merge以后,运行svn status显示的信息,可以通过命令svn merge URL - -dry-run来进行查看
取消修改
在SVN中,如果觉得某个revision做的修改wrong,希望取消,可以使用
svn merge –r 302:303
svn merge –c 303
命令,这里-r表示revision ID的范围,-c直接就是回到303之前
同时,修改完以后,可以通过svn status, svn diff来确认,然后svn commit
这里的修改,只是把正确的内容放到最新的revision中,而不是删除以前的revision,SVN默认是不删除任何内容的,同时如果你去get那个错误的revision,它同样存在
恢复删除的文件/目录
作为SVN来说,最大的好处是,所有的操作都被记录,而且可以查看,找到,进行你要的处理,想要恢复被删掉的文件,可以使用两种方法。
不论哪种,先要找到文件
使用svn log –v命令,-v(- -verbose)选项会显示当前目录下的所有历史修改
然后找到删除这个文件的信息,有那次的revisionID ,以及那次修改的所有内容
这时候恢复:
1.使用svn merge –c命令,但是这个命令会把那次所有的修改回退,这不是你所要的,当然你可以使用svn revert FILE来取消不要的,但是一旦文件很多,就很麻烦
2.使用svn copy ,
使用这个命令,需要知道SVN的一个概念,就是所有版本中的所有文件都可以使用一个方式来唯一表达,这个方式就是PEG,分为2个部分,1是path,2是revision ID
比如:^/trunk/real.c@809指的是在trunk目录下的real.c文件,在809的版本
这时候可以通过svn copy^/trunk/real.c@809./real.c命令来恢复real.c文件到当前目录
摘录合并
指的是,选取你需要的changeset来对branch的content进行merge,使用svn merge
-c revisionID命令来做到,(- - change)
同时在merge之前,可以通过svn diff –c revisionID来对要进行merge的内容的查看
同时你进行了merge之后,以后如果在进行完全的merge,这次merge的内容将被跳过
完整的合并语法
无论是使用svn merge还是svn merge –c都不是完整的merge语法
完整的merge语法,包含3个部分:
1.Merge的revision的起始版本
2.Merge的revision的最终版本
3.Merge的TARGET
简单的说,就是使用–r选项,当然也可以使用PEG模式(URL@REV)
如:
$ 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:200http://svn.example.com/repos/trunk
#省略了当前的工作目录TARGET
没有svn:mergeinfo的合并
svn:mergeinfo是非常重要的SVN property,关系到SVN能否智慧的merge信息
但是在3中情况下,SVN不会创建或设置svn:mergeinfo的信息
1.Merge的源,是与当前TARGET完全无关的,没有共同历史的
2.Merge的源,是其他库的源
3.使用了- -ignore-ancestry (忽略祖先)
合并冲突
Merge出现conflict的时候,在本地会产生3个文件:
filename.working,
filename.left
filename.right
left,right表示的是合并的方向,left应该指的是源,right是TARGET上old文件
合并历史查看
在merge之后,通常可以使用svn log -v来查看TARGET的修改日志,但是日志上没有区分到底是merge的内容,还是自己修改commit的内容,所以使用–g (- -use-merge-history)选项来显示,merge的历史svn log –v –r 390 –g,这个命令显示的包括在trunk目录下的历史,可以让用户来追踪
效果如下
$ svn log -v -r 390
------------------------------------------------------------------------
r390 | user | 2002-11-22 11:01:57 -0600 (Fri, 22 Nov 2002) | 1 line
Changed paths:
M /branches/my-calc-branch/button.c
M /branches/my-calc-branch/README
Final merge of trunk changes to my-calc-branch.
$ svn log -v -r 390 -g
------------------------------------------------------------------------
r390 | user | 2002-11-22 11:01:57 -0600 (Fri, 22 Nov 2002) | 1 line
Changed paths:
M /branches/my-calc-branch/button.c
M /branches/my-calc-branch/README
Final merge of trunk changes to my-calc-branch.
r383 | sally | 2002-11-21 03:19:00 -0600 (Thu, 21 Nov 2002) | 2 lines
Changed paths:
M /branches/my-calc-branch/button.c
Merged via: r390
Fix inverse graphic error on button.
------------------------------------------------------------------------
r382 | sally | 2002-11-20 16:57:06 -0600 (Wed, 20 Nov 2002) | 2 lines
Changed paths:
M /branches/my-calc-branch/README
Merged via: r390
Document my last fix in README.
同时在svn blame命令中,也需要用到-g选项
效果如下:
$ svn blame button.c
…
390 user retval = inverse_func(button, path);
390 user return retval;
390 user }
…
$ svn blame button.c -g
…G
383 sally retval = inverse_func(button, path);
G 383 sally return retval;
390 user }
…
使用了-g就可以知道到底谁提交的修改
关于祖先(ancestry)
简单来说,一个file的revision 99版本是100版本的祖先,但是当101中删除了这个文件,然后102中创建ADD了一个新的同名文件时,99不是102的祖先
祖先的概念,导致了svn diff与svn merge的一个区别
对于svn diff来说不关心祖先,只关心path,也就是说svn diff –r 99 –r 102之间比较就是file的line-by-line的比较
而svn merge时,就会提醒,一个file要被删除,一个新的file要ADD
同样对于svn commit也是一样的道理
提供- -ignore-ancestry选项,就是忽略祖先关系,像svn diff那样比较
使用分支
在SVN上,svn copy创建的branch在本地使用,1是可以通过checkout来得到,2可能因为branch与trunk十分接近,同时又暂时不需要在trunk上工作,可以用svn switch URL切换到
Branch分支上工作
使用svn info | grep “URL”,可以看到当前工作目录的URL
同时对于svn switch不仅仅可以swith整个working copy,还可以switch某个subdictionary或者某个file,这是一旦switch之后本地的工作副本就是一个mix的版本(碰到的情况,为了测试branch的某个功能在trunk下的工作情况),这个mix的版本一样可以update,commit,同时update与commit的对象,都会自动区分,来自branch的subdictionary与file会得到来自branch的update,同时commit到branch
关于TAG
在SVN中tag与branch并没有区别定义,他们之间的区分是人为的概念。TAG也是使用svn copy创建的一个branch,唯一的不同是,不会再对这个branch进行修改提交的情况。
分支与合并命令
Action | Command |
创建一个分支或标签 | svn copy URL1 URL2 |
切换工作副本到分支或标签 | svn switch URL1 |
将分支与主干同步 | svn merge trunkURL ; svn commit |
参见合并历史或适当修改集 | svn mergeinfo SOUCE TARGET |
合并分支到主干 | svn merge - -reintegrate branchURL; svn commit |
复制特定的修改 | svn merge –c REV URL; svn commit; |
合并一个范围的修改 | svn merge –r REV1:REV2 URL ; svn commit; |
让自动合并跳过一个修改 | svn merge –c REV - -record-only URL; svn commit; |
预览合并 | svn merge URL - -dry-run |
丢弃合并结果 | svn revert –R . |
从历史复活某些事物 | svn copy PATH@REV localPATH |
撤销已提交的修改 | svn merge –c REV URL; svn commit; |
感知合并的检查历史 | svn log –g; svn blame –g; |
从工作副本创建一个标签 | svn copy . targetURL |
重新整理分支或标签 | svn mv URL1 URL2 |
删除分支或标签 | svn rm URL |