公司一直采用基于产品的项目定制化开发,为了满足客户的个性化需求,每一个项目代码都与标准产品有一定的差别。项目一旦启动,项目代码就很难跟上产品的完善步伐,因为项目往往有一定程度的个性化调整(假定这些个性化调整都是必须而不得不做的),当产品更新完善以后,除了定期手动更新产品代码外,项目代码就与产品代码脱节了。也曾尝试SVN的分支/标记管理,理论上可以实现,但实际上操作起来比较麻烦,很多粗心的程序员经常搞错搞乱。这里尝试一下利用SVN+Ant来简化项目与产品、项目与项目之间的分支管理,基本工作流程如下:
1、整个产品和项目代码只维护一个SVN版本库,采用典型的trunk/branches/tags模式,每一个定制化项目都在/branches下建一个文件夹,其功能与trunk是同级的;
2、当某一功能点的程序文件有个性化调整时,从产品基础版本新建一个分支(或标签,SVN中分支和标签是一回事,本质上就是另一个路径而已),如从/trunk/war/WEB-INF/jsp/login.jsp建一分支到/branches/project1/war/WEB-INF/jsp/login.jsp;
3、切换当前的工作拷贝到branches下,并进行修改,完成后提交,发布;
4、重新切换当前的工作拷贝到trunk下,继续进行产品修改完善,若属于BUG修复,则人工合并到各分支下;
为了对各项目的定制化部分有个清楚直观全局的认识,简化手工操作,希望通过Ant脚本来简化上述操作。因此需要ANT扩展svnant扩展和foreach扩展的支持。下载地址:http://subclipse.tigris.org/svnant.html和http://sourceforge.net/projects/ant-contrib/files/
在eclipse菜单Windows/Preferences/Ant/Runtime/Classpath/Ant Home Entries下添加上面下载的几个jar:svnjavahl.jar、svnant.jar、svnClientAdapter.jar和ant-contrib-1.0b3.jar。
新建一个svn.properties文件用以做Ant配置,形如:
#产品SVN服务器地址
svn.root = svn://192.168.1.100/product
svn.username = user
svn.password = password
#产品的主干路径
svn.trunk = ${svn.root}/trunk
#产品的项目分支路径,项目名为project,可能还有project1、project2、project3等
svn.branch = ${svn.root}/branches/project
#定制文件列表,相对于eclipse项目根路径,以逗号分隔,以/结尾可支持换行
svn.files = /
war/WEB-INF/config/config.properties,/
war/WEB-INF/config/sqlMapConfig.xml,/
war/WEB-INF/config/struts/struts-config.xml,/
war/WEB-INF/jsp/project/body.jsp,/
war/WEB-INF/jsp/project/menu.jsp,/
war/WEB-INF/jsp/sub/body.jsp,/
war/WEB-INF/jsp/sub/menu.jsp,/
war/WEB-INF/web.xml
新建一个Ant脚本svn.xml文件,首先进行native到ascii的转换,避免显示中文乱码:
<property name="native_props" value="svn.properties" /> <property name="ascii_props" value="svn_ascii.properties" /> <property file="${ascii_props}" /> <target name="native2ascii"> <delete file="${ascii_props}" /> <exec executable="native2ascii"> <arg line="-encoding GBK ${native_props} ${ascii_props}" /> </exec> </target>
定义svnant命令和foreach命令:
<taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" /> <taskdef name="svn" classname="org.tigris.subversion.svnant.SvnTask" />
利用svnant调用基本的SVN命令:
<target name="copy" description="创建分支"> <echo>${svn.file}</echo> <svn javahl="false" username="${svn.username}" password="${svn.password}" failοnerrοr="false"> <copy srcPath="${svn.file}" destUrl="${svn.branch}/${svn.file}" message="分支" /> </svn> </target> <target name="switch.to.branch" description="切换到分支"> <echo>${svn.file}</echo> <svn javahl="false" username="${svn.username}" password="${svn.password}" failοnerrοr="false"> <switch path="${svn.file}" url="${svn.branch}/${svn.file}" /> </svn> </target> <target name="switch.to.trunk" description="切换到主干"> <echo>${svn.file}</echo> <svn javahl="false" username="${svn.username}" password="${svn.password}" failοnerrοr="false"> <switch path="${svn.file}" url="${svn.trunk}/${svn.file}" /> </svn> </target>
通过foreach命令根据配置文件中配置的定制化程序文件列表调用相应SVN命令实现版本的切换:
<target name="copy.bat" description="批量创建分支"> <foreach target="copy" list="${svn.files}" param="svn.file" delimiter="," /> </target> <target name="switch.to.branch.bat" description="批量切换到分支"> <foreach target="switch.to.branch" list="${svn.files}" param="svn.file" delimiter="," /> </target> <target name="switch.to.trunk.bat" description="批量切换到分支"> <foreach target="switch.to.trunk" list="${svn.files}" param="svn.file" delimiter="," /> </target>