SVN分支/主干Merge操作小记
一、前言
说来惭愧,鄙人从事开发多年,使用svn已经好几个年头了,但是却仅限于update、commit、compare之类的操作,最近想到github上学习别人写的NIO源码,顺便去熟悉git的使用,但是一想到svn,我心里虚了:用了那么多年却对其一知半解,就连最基本的权限分配都没有做过,更别说进行分支拉取和合并了,何谈去get其他技能?做技术的还是要踏实一点,近一年来,我都在对之前未深入的领域进行扫盲,所以,注定svn是绕不过的坎,于是乎开始各种查资料,安装svn服务端(Virtual SVN)和客户端(TortoiseSVN),比对网上的博文进行各种尝试,不能说过程痛苦,但是当你在云里雾里摸索的时候挺难受的吧(顺便说下,在学习的时候精力一定要集中!对我而言,顺便塞上耳塞听音乐工作效率是事半功倍,哈哈哈~)~不废话了,今天这篇博文就讲讲SVN里面比较高级的操作:创建分支(branch)、将主干(trunk)中的代码合并到分支(branch)、将分支(branch)中的代码合并到主干(trunk)中~
二、正文
说到分支和主干,我想不少coder也是比较少接触吧,毕竟很多时候,我们想着的还是如何赶进度~之所以出现分支和主干,就是希望主干和分支两份代码可以各自进行独立的管理互不影响,在需要的时候再进行合并。试想这样一种场景:公司项目已经完成一个阶段的开发计划,这时候拉取一个branch专门用来测试以及BUG修复,而原先trunk上面的代码还可以继续往下开发,互不影响,等测试的branch问题修复之后,将这个branch“合并”回trunk。这样trunk和branch可以在互不干扰的情况下各自做自己的事儿,最后再进行整合,合并过程中有可能会有冲突,这个并不麻烦,等出现冲突的时候自行百度,我相信你们可以解决的,如果还是晕乎乎,欢迎加群交流~
接下来我就来说说如何创建分支(branch)、将主干(trunk)中的代码合并到分支(branch)、将分支(branch)中的代码合并到主干(trunk),首先说明一下笔者当前测试环境:
- Virtual SVN 1.9.5(传送门:https://www.visualsvn.com/server/download/)
- TortoiseSVN 1.9.5(传送门:https://sourceforge.net/projects/tortoisesvn/files/1.9.5/Application/)
准备工作(以上客户端服务端自行安装,除了安装路径看自己喜好之外,其他都按照默认设置,点击“下一步”吧):
1)创建repository
打开Virtual SVN,在左侧列表中,右键Repositories,新建一个repository,名字随意,格式笔者是选择FSFS,Repository Structure笔者选择Single-project repository******,这样方便后面的描述,为了测试的方便,在选择“Repository Access Permissions”的时候,选择所有人SVN的user都有访问这个repository的权限(user可以在Virtual SVN的左侧列表Users节点右键,进行新增)
2)Check out trunk目录到本地
首先复制刚刚新建的repository下trunk的SVN URL
在本机随意一个目录新建一个空目录,比如笔者在d盘新建了一个svntrunk的目录,然后右键=>SVN Check out,将trunk的svn地址复制到“URL of repository”那一栏,然后点击“OK”
3)在D:\svntrunk目录下新建一个目录(名称设为project),然后在新建的目录下新增两个text文件:1.txt(文件内容:111111),2.txt(文件内容:222222),然后右键这个project目录,先Add,然后进行commit:
4)创建分支(branch)(唠叨一下,分支是创建在SVN服务器的repository中,而merge是合并在开发者本地)
右键D:\svntrunk\project文件夹,选择TortoiseSVN->Branch/tag,在弹出的对话框中,To path输入分支存放在repository的相对目录,这边注意:project01不能先创建,不然会报project01已经存在,不能创建分支!在log message中输入创建分支的日志,这对后续了解这个分支创建的目的有一定意义。在log message输入栏下面,还有一个Create copy in the repository from的选项,这个选项的目的是为了让开发者选择用哪份源码作为创建的版本 ,第一个是trunk中最新的版本,第二个用户可以选择trunk中指定的版本(通过序号标识),第三个是将工作拷贝作为创建分支的版本
上步点击OK之后,创建分支完成,就是这么简单,现在请先记住,我们是以trunk中版本序号是2的工程作为创建分支的版本,这个对后续的合并有意义~(这边顺便说下,在一个repository,版本号是一个全局资源,不管是trunk、branch还是tag,他们使用的版本号不会重复,比如现在trunk已经用掉2这个版本号,那么分支就只能往下一个,用3)
5)分支(branch)中的代码合并到主干(trunk)
首先,就像之前将主干(trunk)Check out到本地一样,将svn服务器上面的分支(branches)Check out到D盘svnbranches目录:
现在假设主干(trunk)和分支(branche)并行开发,主干(trunk)project下1.txt的文件内容改为121212,分支(branch)中project1下面增加一个3.txt文件,文件内容为:333333
右键主干中project文件夹,选择TortoiseSVN->Merge,这时会弹出一个Merge type让你选(TortoiseSVN1.9.5这个版本只有两个选项,网上有些博文有三个选项),Merge type的选择还是很有讲究,并且也是很容易搞错的,下面会具体来说说:
我们先来说说“Merge a range of revisions”这个选项:
我们选中这个选项,然后点击“Next”,会看到如下界面,因为我们是要将分支(branch)合并到主干(trunk),所以这边URL to merge from选项要选择服务器上面需要合并到主干(trunk)的分支(branch)地址(注:前面有提过,合并是合并到本地的working copy,所以一般合并之前,最好将本地working copy代码先更新一遍,有冲突的解决冲突,并且将未提交的代码提交,以防在合并之后,未提交的代码丢失),这边有个Revision range to merge选项,当选择all revisions进行merge的时候,TortoiseSVN做了怎么样的操作呢?其实就是:diff and apply。diff是比较URL to merge from指定的工程最新一个版本和最初的一个版本的差异,假设最新版本是r-last,最初的版本r-first,r-last相对r-first而言,增加了文件a,修改了文件b,那么在合并的时候,就将“增加文件a,修改文件b”的操作应用在本地的working copy上面去,这就完成了合并;假设选择的是specific range,那么用户可以选择一个版本范围,也可以单独指定一个版本或者不填写任何值(此时相当于选all revisions),假设用户指定了版本r1-r3,其中r1新增了文件a,r2新增了文件b,r3删除了文件c,那么在合并的时候TortoiseSVN就会将“新增文件a,新增文件b,删除文件c”应用于本地的 working copy,这样就完成了合并~
(ps:这边还有一个Reverse merge复选框,恢复之前的合并。假设我们刚刚做的merge有问题,需要将本地的working copy恢复成merge之前的,那么就需要将之前应用于本地working copy的操作全部回退,操作和merge基本一样,只是最后,需要复选这个Reverse merge复选框)
上步选择了Revision range to merge之后,点击“Next”,进入如下界面,这时我们就可以看到如下界面:
全部使用默认的选项,然后在点击Merge之前,可以先点击Test merge按钮,测试一下merge之后的效果:
如上图所示,分支(branch)版本新增的3.txt文件最终会合并到本次working copy中,最后将本地working copy中的3.txt提交到svn中,这样就完成了分支到trunk的合并了~
我们再来说说这个“Merge two different trees”,从它自己选项的解释来看,是将两个不同的分支(branch)合并到本地working copy中,当然,我们也可以用这个选项将分支(branch)修改的内容合并回主干(trunk)。选择Merge two different trees,点击Next
上步之后,会出现如下对话框,注意,我们现在是将分支(branch)合并回主干(trunk),这个时候,我相信很多人想当然的认为Fom处填写的应该是分支(branch)的URL,而To,应该是主干(trunk)的URL,因为是从分支(branch)到主干(trunk)啊,然后事实并非如此!之前在创建分支(branch)这一节,有让读者记住拉取分支(branch)时,主干(trunk)的版本号,当时主干(trunk)的版本号是2,所以From处的URL应该写主干(trunk)的URL,Revision应该选2(其实trunk revision为2的版本,其实也就是branch的第一个版本,所以这边From可以选择主干拉取分支的版本,也可以选取分支最开始的版本),而To处的URL应该选分支的URL,Revision选HEAD Revision,也就是选最新的分支版本。现在就来说说为什么要这样填写:此处进行merge的时候,进行的操作也是diff and apply,将To处URL和revision指定的某个版本,与From处URL和Revision指定的某个版本进行对比,对比是有顺序的,这个怎么理解呢?比如现在To处的为工程project1,From处的为工程project,如果project1相对于project而言,有文件a,没有文件b,换句话说project1相对于project而言,“新增了a,删除了b”,那么此处merge的结果就是会将“新增a,删除b”的操作应用于本地working copy的工程,那为什么From处的project不能指定为最新的Revision呢,既HEAD Revision?试想一下,假如主干(trunk)在拉取了分支(branch)之后,主干(trunk)和分支(branch)都有在并行开发,那么必然主干(trunk)上会有新增的功能,这样就会有新增的代码,这些代码在分支(trunk)上并不存在,在To和From比较过程中,就会出现“删除xxx”的操作,这在merge过程中会应用在本地working copy中,本来这个“xxx”是主干新功能的代码,在将分支合并过来的时候,不应该删除,所以不能用主干最新的版本和分支最新的版本做对比,应该是将当时拉取分支的时候的主干版本和当前最新的分支版本进行对比,应用到本地working copy中才对,所以这边的From必须选取当时拉取当前分支的主干版本,不然主干上面新增的代码会丢失,之前我对From和To的顺序,以及revision的选取也是迷糊了大半天,我希望对读者而言,我这边已经说清楚了~如果还有什么不清楚的欢迎加群交流~
上步之后,点击Next,进入下面这个页面,同样,在最终merge之时,点击Test merge
点击Test merge之后,可以看到最终合并之后的效果
6)主干(trunk)中的代码合并到分支(branch)
这边的操作和分支(branch)合并到主干(类似),需要注意的是,Merge type如果选择“Merge a range of revisions”,那么范围的起始版本应该为拉取分支时的主干版本,结束版本应该为trunk最新的版本;如果选择“Merge two different trees”,那么From必须是选取拉取分支时的主干的版本,或者分支的第一个版本,To必须是主干最新的版本
最后总结一下:不管选取哪个Merge type,都能完成主干到分支、分支到主干的合并,需要注意的是,在选择“Merge two fifferent trees”时From和To对应的URL所代表的含义(5)分支(branch)中的代码合并到主干(trunk)这一节有讲),并且需要了解合并的原理,那么拉取分支和合并的操作并不是什么难事。如有什么疑问,请加群交流~
三、链接
1、http://blog.csdn.net/zhuyong0722/article/details/8965095
2、http://blog.csdn.net/wjtxt/article/details/8623262
3、http://www.cnblogs.com/firstdream/p/5632296.html
四、联系本人
为方便没有博客园账号的读者交流,特意建立一个企鹅群(纯公益,非利益相关),读者如果有对博文不明之处,欢迎加群交流:261746360,小杜比亚-博客园