提到语义化版本,你可能不是很熟悉,但是这几乎是每个开发者都接触的非常多的一种版本管理方式,当你所使用的软件的版本以比如GitLab 12.10.5的方式进行版本的介绍的时候,这就是一种典型的语义化版本方式。这篇文章以中文版的语义化版本说明为基础进行使用解释。
什么是语义化版本(Semantic Versioning)相较于定义,建议先记住这样一个示例更容易理解:
版本格式:主版本号.次版本号.修订号 版本示例:12.10.5
官方说明: 主版本号:当你做了不兼容的 API 修改, 次版本号:当你做了向下兼容的功能性新增, 修订号:当你做了向下兼容的问题修正。 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
解读:主版本号一般对应于大版本,主要在于不向下兼容的情况出现。次版本号为小版本号,对应于一般向下兼容的的特性开发,而修订号一般对应于bug修正。 编译信息等可以追加至修订号后,作为延伸扩展。
引入的原因- 依赖地狱(dependency hell):依赖关系管理不当,可能会导致各种风险,尤其是各种组件使用地越来越多的当下。
- 版本特性的增强的利用和不能向下兼容的风险的控制,没有良好的管理,这两点就足以构成复杂依赖使用下的各种问题的出现,有可能为了某个组件的更新,被迫升级所有相关依赖,最后尴尬的发现其中有一种还不支持这个组件的更新版本。
- 版本管理需要提供一种规范性的约定俗成的方式,大家都来遵循。使得大家能够见到版本号就能立即理解一些基础内容,比如此次更新是否向下兼容,是特性增强还是bug修正。
建议1: 初始开发阶段(0.y.z)的版本控制方式,建议以0.1.0作为初始化开发版本,后续每次发型递增版本号。
建议2: 当软件被用于正式环境,已经有了稳定的API(功能性对外暴露的接口或者说明),就可以作为1.0.0版本。
建议3: 语义化版本并不会阻碍快速迭代开发,它就是为了更好地管理快速迭代开发过程中的版本管理的。对于迭代开发坚持使用语义化版本进行版本控制。
建议4: 即使很小的不向下兼容的更新都应该造成主版本号的更新,在设计阶段需要有一定的前瞻性,不然可能就会出现235.2.3这样的版本号,主版本号发行不兼容的版本,所付出的代价可能是很大的,尤其作为基础组件被引用时,此类发版前往往需要进行成本和效益的综合评估。
建议5: 发错版本号,比如将不兼容的问题当作小版本进行了发布,严格来说需要进行修正,并发行一个新的此版本号来更正并恢复向下兼容,但是也不能去修改已发行的版本,尽可能的将问题的信息记录到Release Note中,使得使用者对此问题有所了解。
建议6: 对于即将弃用的功能,首先应该更新你的Release Note和说明文档让使用者知道这个改变,然后在适当的时机将弃用的功能透过新的次版本号发布。在新的主版本完全移除弃用功能前,至少要有一个次版本包含这个弃用信息,这样使用者才能平顺地转移到新版 API。
建议7: 语义化版本虽然对于版本的字串长度没有限制,但是过长显然是不太合适的,比如超过255的话就已经显得很夸张,建议版本号中不要包含过多内容,即使包含,可以通过信息压缩来实现。
语义化版本控制规范(SemVer)以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。(译注:为了保持语句顺畅, 以下文件遇到的关键词将依照整句语义进行翻译,在此先不进行个别翻译。)
-
使用语义化版本控制的软件必须(MUST)定义公共 API。该 API 可以在代码中被定义或出现于严谨的文件内。无论何种形式都应该力求精确且完整。
-
标准的版本号必须(MUST)采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数,且禁止(MUST NOT)在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须(MUST)以数值来递增。例如:1.9.1 -> 1.10.0 -> 1.11.0。
-
标记版本号的软件发行后,禁止(MUST NOT)改变该版本软件的内容。任何修改都必须(MUST)以新版本发行。
-
主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
-
1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。
-
修订号 Z(x.y.Z | x > 0)必须(MUST)在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。
-
次版本号 Y(x.Y.z | x > 0)必须(MUST)在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用时也必须(MUST)递增。也可以(MAY)在内部程序有大量新功能或改进被加入时递增,其中可以(MAY)包括修订级别的改变。每当次版本号递增时,修订号必须(MUST)归零。
-
主版本号 X(X.y.z | X > 0)必须(MUST)在有任何不兼容的修改被加入公共 API 时递增。其中可以(MAY)包括次版本号及修订级别的改变。每当主版本号递增时,次版本号和修订号必须(MUST)归零。
-
先行版本号可以(MAY)被标注在修订版之后,先加上一个连接号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。数字型的标识符禁止(MUST NOT)在前方补零。先行版的优先级低于相关联的标准版本。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。
-
版本编译元数据可以(MAY)被标注在修订版或先行版本号之后,先加上一个加号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。当判断版本的优先层级时,版本编译元数据可(SHOULD)被忽略。因此当两个版本只有在版本编译元数据有差别时,属于相同的优先层级。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
-
版本的优先层级指的是不同版本在排序时如何比较。判断优先层级时,必须(MUST)把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较(版本编译元数据不在这份比较的列表中)。由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较,例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。例如:1.0.0-alpha < 1.0.0。有相同主版本号、次版本号及修订号的两个先行版本号,其优先层级必须(MUST)透过由左到右的每个被句点分隔的标识符来比较,直到找到一个差异值后决定:只有数字的标识符以数值高低比较,有字母或连接号时则逐字以 ASCII 的排序来比较。数字的标识符比非数字的标识符优先层级低。若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。范例:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。
# 参考文档 https://semver.org/lang/zh-CN/spec/v2.0.0.html