概述/背景
项目在开发过程中的版本,和在发布时的版本应该有所区别。发布的版本应该保证一个版本号对应唯一的内容。
之前遇到过一个项目,因为pom中的版本号没有-SNAPSHOT
,导致两个环境依赖的项目虽然版本号相同,其实不是同一个。当时得出结论:相同的版本号只应该对应一个内容。
后来系统学习了下Maven,才具体了解到Maven体系中关于项目版本的标准,这里分享出来,希望大家在维护项目版本的时候有据可依。
另外,Maven中的版本管理需要结合软件版本控制工具使用,如Git、SVN等。虽然目前Git的使用已经很普遍了,我的工作环境使用的是SVN,就以SVN为例进行介绍。
Maven范围的版本和SVN范围的版本有不同的含义。前者面向的是项目,代码多次修改,项目的版本号可以不变;后者面向的是代码,每一次修改都是一个不同的版本。下文所说的版本一般是指项目的版本,特殊情况下会说明是代码版本。
快照版本和发布版本
快照版本对应开发过程中的版本,特点是快速的迭代更新,同样的版本号对应的是项目在一段时间内的开发过程。
发布版本应该是一个稳定的版本,它应该对应项目在某个时刻的状态 —— 它对应唯一的代码版本。
快照版本使用-SNAPSHOT
后缀。
在Maven体系中的区别
Maven解析依赖的一般机制是:先从本地仓库找,找不到再从远程仓库找。换言之,在本地仓库找到了,就不会再去找远程仓库。
如果有2个项目并行开发,其中一个项目B依赖于另一个项目A。想象一下A和B都是持续更新的,项目B的开发人员如何确保能实时获取项目A的最新内容?
方案一:项目B的开发人员,每次构建之前都手动从本地仓库删除项目A,这样构建的时候就会从远程仓库下载最新的A。
方案二:项目B的开发人员,迁出项目A的代码,自己将A项目安装到本地仓库。
这两个个方案都不是Maven体系推荐的做法,方案二让项目B的开发人员不得不去搭建项目A的开发环境,而且项目A如果出现代码问题,项目B的开发人员可能就无能为力了。方案一增加了需要人工介入的工作量。
Maven使用SNAPSHOT
来解决这个问题。如果项目依赖的是一个SNAPSHOT版本的依赖,Maven会定期从远程仓库获取最新的内容,默认频率是一天一次。也可以使用-U参数来强制更新。
所以,项目A使用SNAPSHOT版本,项目B就可以定期或者实时获取项目A的最新内容。
反之,如果项目A没有使用SNAPSHOT
,项目B在第一次从远程仓库下载项目A到本地仓库之后,就一直使用本地仓库的这个备份。即使项目A更新了,项目B也不会知道,除非人工删除了项目A在本地仓库的副本。
所以,开发过程中的版本,应该使用SNAPSHOT
版本。
发布版本的版本号约定
一般的情况下是下面这种结构:
<主版本>.<次版本>.<增量版本> 比如 1.1.2
各版本的作用如下:
- 主版本
项目的重大架构变更 - 次版本
较大范围的功能变化 - 增量版本
大量或紧急bug修复
这只是一个粗略的划分,大家可以根据自己的情况讨论每一个版本的使用场景。
通常主版本、次版本都会有,增量版本视情况而定。
更进一步的情况,可以添加里程碑版本,版本的结构如下:
<主版本>.<次版本>.<增量版本>—<里程碑版本> 如 3.1.2-alpha-1
里程碑版本表示达成项目的某个里程碑,但通常不够稳定。大部分的公司应该不会使用里程碑版本,在此略过不表。
版本维护流程
主干、标签和分支
- 主干
无需多说 - 标签
标记某个有意义的代码版本,每一个发布版本都应该打一个标签。 - 分支
用于并行开发,通常用于已有版本的bug修复。
流程demo
- 在主干进行1.0.0-SNAPSHOT的开发,开发完成之后提交修改的代码到主干。修改版本为1.0.0,再次提交,并添加标签。
- 随后将版本改为1.1.0-SNAPSHOT,提交。然后开始新一轮的开发,完成之后提交代码,修改版本为1.1.0,再次提交并打标签。
- 接着将版本号改为1.2.0-SNAPSHOT,提交,并开始新一轮的开发,在开发过程中1.1.0遇到一个紧急的bug,新建分支并1.1.1-SNAPSHOT,修改版本号为1.1.1-SNAPSHOT,提交并开始1.1.1-SNAPSHOT的开发。
- 1.1.1-SNAPSHOT开发完成,提交代码。修改版本号至1.1.1,提交并打上标签。此时可以及时把1.1.1发布出去。同步分支到主干。
- 随后,1.2.0-SNAPSHOT开发完成..
版本号的修改应该作为一次单独的提交。在发布的时候,项目版本号初始为SNAPSHOT版本,提交完所有的代码之后,修改版本号为发布版本,再提交;这次提交只修改版本号。
在开始新一轮的开发过程时,修改版本号为新的SNAPSHOT,然后立即提交而不是修改代码,版本号提交之后再开始开发,这次提交只修改版本号。
SVN相关操作
SVN简单介绍
SVN是一个很简单的版本控制工具,你可以下载VisualSVN Server来搭建自己的SVN服务器。
SVN的代码主要是在仓库里管理的,如上图demo就是一个仓库。完整的仓库目录结构如下:
仓库目录(Repositories)
|-- 仓库1
|-- 项目1
|-- 主干(trunk)
|-- 项目代码
|-- 标签目录(tags)
|-- 标签1
|-- 项目代码
|-- 分支(branches)
|-- 分支1
|-- 项目代码
可以看到,SVN的每一个标签或者分支,都是一份完整的代码副本。
与仓库同一个级别的是用户等其他,可以控制对仓库的读写权限,具体没有深入研究,大家有需要自己研究下。
SVN操作
这里介绍上文版本维护流程中涉及到的操作。这里以命令的方式介绍,使用客户端界面的自己找一下操作的位置。
初始化项目
初始化项目首先要在VisulSVN Server的具体仓库下新建一个项目结构:
仓库-> 右键 -> 新建 –> Project Structure …
之后会生成一个标准的项目结构,包含了trunk、branches、tags,没有代码。
获取trunk的url地址,通过trunk -> 右键 -> Copy URL…
在本地项目所在目录,输入以下命令:
svn import -m "initial import" . https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk
添加标签
版本号修改为发布版本之后,应该立即对当前状态添加一个标签:
svn copy https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags/1.0-RELEASE -m "tag 1.0-RELEASE"
创建分支
svn copy https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags/1.0-RELEASE https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT -m "create branch 1.0.1-SNAPSHOT"
可以看到,添加标签和创建分支本质上都是复制。
切换分支
svn switch https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT
合并分支
svn merge https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT
合并分支的时候,pom文件中的版本号会有冲突。一般选择使用当前的版本号。
Maven的release插件
在使用自动化的插件之前,建议先手动执行上面的流程,熟悉版本维护的流程之后,再去使用自动化插件。
配置pom文件
pom文件需要添加scm配置和插件配置。scm是Software configuration management的缩写。
<project>
...
<scm>
<connection>scm:svn:https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</connection>
<developerConnection>scm:svn:https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</developerConnection>
<url>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</url>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tagBase>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags</tagBase>
<branchBase>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches</branchBase>
</configuration>
</plugin>
</plugins>
</build>
</project>
scm中配置了trunk的url,connection和developerConnection的值都以scm开头,之后跟着版本控制工具的类型svn。除了svn之外,Maven还支持其他的工具,如git。
插件里配置了标签的url和分支的url,其实如果项目的结构是标准的,trunk、tags和branches在同一级,可以不用配置这两项。
配置完之后,就可以通过mvn命令来自动发布、打标签、创建分支了。
自动发布
插件把发布分为2步,第1步执行上文中版本维护流程中介绍的发布流程,第2步使用mvn deploy
部署构建至仓库。第1步由插件的prepare
来完成,第2步由插件的perform
目标来完成。
如果prepare
执行失败,可以通过rollback
目标来回滚,但是prepare
生成的标签需要手动删除。
release:prepare
prepare负责预发布,在prepare之前,需要确保所有的修改都已经提交了,而当前的pom文件中的版本号还没有升级为发布版本号。
prepare所做的工作有:
- 检查系统是否有未提交的代码
- 询问用户发布版本号、标签和下一个开发版本号,并提供默认值。
What is the release version for "demo-version"? (com.hikvision.demo:demo-version) 1.2: : What is SCM release tag or label for "demo-version"? (com.hikvision.demo:demo-version) demo-version-1.2: : What is the new development version for "demo-version"? (com.hikvision.demo:demo-version) 1.3-SNAPSHOT: :
- 修改pom-根据用户的输入,将快照版本升级为发布版本
- 修改pom-根据用户的输入,将scm中的地址改为标签对应的地址
- 执行Maven构建
- 提交pom变更
- 根据用户的输入,新建标签
- 修改pom-根据用户的输入将version升级为新的快照版本,将scm信息更新。
- 提交pom变更。
上述的内容,正是我们在升级项目版本需要做的事情。
使用命令:mvn release:prepare
。
release:rollback
回退release:prepare
的所执行的操作,并提交。但是历史记录会保留,创建的标签页不会删除。
使用命令:mvn release:rollback
。
release:perform
执行版本发布。是基于发布版本标签地址所对应的代码进行mvn deploy的结果。
使用命令:mvn release:perform
。
release:branch
自动创建分支。
使用命令:
mvn release:branch -DbranchName=1.1.1 -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false
参考
- 《Maven实战》 - 许晓斌