Maven 版本管理
一个健康的项目通常有一个长期、合理的版本演变过程。例如 Maven 本身的版本也比较多,如最早的 Maven1;Maven2 有 2.0.9、2.0.10、2.1.0、2.2.0、2.2.1 等各种版本;而最新的 Maven3 则拥有 3.0- alpha-1、3.0- alpha-2、3.0- alpha-7、3.0-beta-l 等版本。除了这些对外发布的版本之外, Maven 特有的快照版本的概念。这些版本中的每个数字代表了什么? alpha、beta 是什么意思?快照版和发布版的区别是什么?我们应该如何科学地管理自己的项目版本?本章将会详细解答这些问题。
阅读本章的时候还需要分清版本管理(Version Management)和版本控制(Version Control)的区别。版本管理是指项目整体版本的演变过程管理,如从 1.0- SNAPSHOT 到 1.0,再到 1.1- SNAPSHOT。版本控制是指借助版本控制工具(如 Subversion)追踪代码的每一个变更。本章重点讲述的是版本管理。
版本管理关心的问题之一就是这种快照版和发布版之间的转换。项目经过了一段时间的 1.0-SNAPSHOT 的开发之后,在某个时刻发布了 1.0 正式版,然后项目又进入了 1.1-SNAPSHOT 的开发,这个版本可能添加了一些有趣的特性,然后在某个时刻发布 1.1 正式版。项目接着进入 1.2-SNAPSHOT 的的开发。由于快照对应了项目的开发过程,因此往往对应了很长的时间,而正式版本对应了项目的发布,因此仅仅代表某个时刻项目的状态。
1. Maven 版本号
Maven 的的版本号定义约定是这样的:
<主版本>.<次版本>.<增量版本>-<里程碑版本>
看一个实际的例子,这里有一个版本:1.3.4-beta-2。“1” 表示了该版本是第一个重大版本;“3” 表示这是基于重大版本的第三个次要版本;“4” 表示该次要版本的第四个增量;最后的“beta-2” 表示该增增量的某一个里程碑。
主版本和次版本之间,以及次版本和増量版本之间用点号分隔,里程碑版本之前用连字号分隔。下面解释其中每一个部分的意义:
- 主版本:表示了项目的重大架构变更。例如, Maven2和 Maven1相去甚远; Struts1和 Struts2采用了不同的架构; Junit4较 Junit3增加了标注支持。
- 次版本:表示较大范围的功能增加和变化,及Bug修复。例如 Nexus1.5较1.4添加了LDAP的支持,并修复了很多Bug,但从总体架构来说,没有什么变化。
- 增量版本:一般表示重大Bug的修复,例如项目发布了1.4.0版本之后后,发现了个影响功能的重大Bug,则应该快速发布一个修复了Bug的1.4.1版本。
- 里程碑版本:顾名思义,这往往指某一个版本的里程碑。例如, Maven3 已经发布了很多里程碑版本,如 3.0-alpha-1、3.0-alpha-2、3.0-beta-1 等。这样的版本与正式的 3.0 相比,往往表示不是非常稳定,还需要很多测试。
需要注意的是,不是每个版本号都必须拥有这四个部分。一般来说,主版本和次版本都会声明,但增量版本和里程碑就不一定了。例如,像 3.8 这样的版本没有增量和里程碑 2.0-bea-l 没有增量。但我们不会看到有人省略次版本,简单地给给出主版本显然是不够的。
当用户在声明依赖或插件未声明版本时, Maven 就会根据上述的版本号约定自动解析最新版本。这个时候候就需要对版本号进行排序序。对于主版本、次版本和增量版本来说,比较是基于数字的,因此 1.5 > 1.4 > 1.3.11 > 1.3.9。而对于里程碑版本, Maven 则只进行简单的字符串比较,因此会得到 1.2-beta-3 > 1.2-beta-11 的结果。这一点需要留意。
2. 主干、标签与分支
使用版本控制工具时我们都会遇到主干(trunk)、标签(tag)和 分支(branch)的概念。这里再详细将这几个概念阐述一下,因为理解它们是理解 Maven 版本管理的基础。
- 口主干:项目开发代码的主体,是从项目开始直到当前都处于活动的状态。从这里可以获得项目最新的源代码以及几乎所有的变更历史。
- 分支:从主干的某个点分离出来的代码拷贝,通常可以在不影响主干的前提下在这里进行重大 Bug 的修复、或者做一些实验性质的开发,如果分支达到了预期的目的,通常发生在这里的变更公被合并(merge)主干中。
- 标签:用来标识主干或者分支的某个点的状态,以代表项目的某个稳定状态,这通常就是版本发布时的状态。
下图下方最长的箭头表示示项项目的主干,项目最初的版本是 1.0.0-SNAPSHOT,经过段时间的开发后,1.0.0 版本发布,这个时候就需要打一个标签,图中用一个长条表示。然后项目进入1.1.0-SNAPSHOT 状态态,大量的开发工作都完成在主干中,添加了一些新特性并修复了很多 Bug 之后,项目 1.1.0 发布,同样,这时候需要打另一个标签。发布过后,项目进人 1.2.0- SNAPSHOT 阶段,可这个时候用户报告 1.1.0 版本有一个重大的 Bug,需需要尽快修复,我们不能在主干中修 Bug,因为主干有太多的变化,无法在短时间内测试完毕并发布,我们也不能停止1.2.0- SNAPSHOT 的开发,因此这时候可以基于 1.1.0 创建一个 1.1.1-SNAPSHOT 的分支,在这里进行 Bug 修复,然后为用户发布一个 1.1.1 增量版本,同时打上标签。当然,还不能忘了把 Bug 修复涉及的变更合并到 1.2.0-SNAPSHOT 的主干中。主干在开发一段时间之后,发布 1.2.0 版本,然后进入到新版本 1.3.0-SNAPSHOT 的开发过程中。
图 2 展示的是一个典型的项目版本变化过程,这里涉及了快照版与发布版之间的切换、 Maven 版本号约定的应用,以及版本控制系统主干、标签和分支的使用。这其实也是一个不成文的行业标准,理解这个过程之后,不仅仅能够更方便地学习开源项目,也能对项目的版本管理更加标准和清晰。
3. 自动化版本发布
本章前几节已经详细介绍了版本发布时所需要完成的工作,读者如果愿意,则完全可以手动地执行这些操作,检查是否有未提交代码、是否有快照依赖、更新快照版至发布版、执行 Maven 构建以及为源代码打标签等如果对这一过程不是很熟悉,那么还是应该一步一步地操作一遍,以得到最直观的感受。
当熟悉了版本发布流程之后,就会希望借助工具将这一流程自动化。 maven-release-plugin 就提提供了这样的功能,只要提供一些必要的信息,它就能帮我们完成上述所有版本发布所涉及的操作。下面介绍如何使用 maven-release-plugin 发布项目版本。
maven-release-plugin 主要有三个目标,它们分别为:
-
release:prepare 准备版本发布,依次执行下列列操作:
- 检查项目是否有未提交的代码。
- 检查项目是否有快照版本依赖。
- 根据用户的输入将快照版本升级为发布版。
- 将 POM 中的 SCM 信息更新为标签地址。
- 基于修改后的 POM 执行 Maven构建。
- 提交 POM 变更。
- 基于用户输人为代码打标签。
- 将代码从发布版升级为新的快照版。
- 提交 POM 变更。
-
release:rollback 回退 release:prepare所执行的操作。将 POM 回退至 release:prepare之前的状态,并提交。需要注意的是,该步骤不会删除 release:prepare 生成的标签,因此用户需要手动删除。
-
release:perform 执行版本发布。签出 release:prepare 生成的标签中的源代码,并在此基础上执行 mvn deploy 命令打包并部署构件至仓库。
要为项目发布版本,首先需要为其添加正确的版本控制系统信息,这是因为 maven-release-plugin 需要知道版本控制系统的主干、标签等地址信息后才能执行相关的操作。一般配置项目的SCM 信息:
<project>
<scm>
<connection>scm:http://admin@localhost:8080/gitblit/r/~admin/osgi.git</connection>
<developerConnection>scm:http://admin@localhost:8080/gitblit/r/~admin/osgi.git</developerConnection>
<url>http://admin@localhost:8080/gitblit/r/~admin/osgi.git</url>
</scm>
</project>
connection 元素表示一个只读的 scm 地址,而 developerConnection 元素表示可写的 scm 地址,ur 则表示可以在测览器中访问的 scm 地址。为了能让 Maven 识别, connec-thon 和 developerConnection 必须以 scm 开头,冒号之后的部分表示版本控制工具类型(这里是git)。接下来才是实际的 scm 地址,该例中的 connection 使用了 http 协议,而 developerConnection 则由于涉及写操作,使用 http 协议进行了保护。