语义化版本
目录
什么是语义化版本
语义化版本是一种描述软件的方式,使用一组规则描述版本的变化,采用 主版本号.次版本号.修订号 的格式
主版本号 (Major):当软件进行不兼容的 API 变更 (breaking changes),主版本号递增次版本号和修订号重置为 0
次版本号 (Minor):当软件添加了新功能,但保持向后兼容时,次版本号递增,修订号重置为 0
修订号 (Patch):当软件进行向后兼容的 bug 修复或小更新,修订号递增
先行版本号及版本编译信息可以加到
Major.Minor.Patch
之后作延申
举个例子
假设当前有一个版本号为 1.0.0
的软件包供给外部软件调用,当前软件包中有一个函数 example(a: string, b: number): string {}
example
函数体存在 bug,修复 bug 后未在软件中引入新的 API,该函数仍能实现预期的功能。这就是仅进行 bug 修复,未添加新功能,未发生不兼容的 API 修改,版本号变更为1.0.1
- 软件包中新增了
example
的函数重载,如:example(a: string, b: number, c?: boolean): string {}
,用户原有的调用依旧返回预期结果,当用户的example
函数传入c
参数时,返回值发生变化。新增了一个函数重载的功能,未发生不兼容的 API 修改,版本号变更为1.1.0
example
函数新增了一个参数,如:example(a: string, b: number, c: boolean): string {}
,用户原有的调用会报错提示缺少参数,这时就发生了不兼容的 API 修改,版本号变更为2.0.0
FAQ
如何处理初始阶段的版本
- 软件的主版本号为
0.y.z
是一种特殊状态,这意味着该软件处于开发初始阶段,一切都可能随时被改变 - 最简单的做法是以
0.1.0
作为初始化开发版本,并在后续的每次发行时递增次版本号
- 软件的主版本号为
如何判断发布
1.0.0
的时机- 当软件被部署到生产环境中开始被正式使用,它应该已经达到了
1.0.0
- 此时的软件已经有了一系列稳定的 API 在被使用者依赖,并开始需要考虑向后兼容的问题
- 当软件被部署到生产环境中开始被正式使用,它应该已经达到了
v.1.2.3
是语义版本吗不是。
v.1.2.3
是标签名称,1.2.3
是语义版本shgit tag v1.2.3 -m "Release version 1.2.3"
如何决定版本的优先级:判断优先级时,必须把本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较
- 正式版本:依次比较主版本号、次版本号、修订号,数字较大的优先级较高 (如:
2.0.0
>1.0.0
) - 相同版本:正式版本的优先级高于先行版本 (如:
1.0.0
>1.0.0-alpha
) - 先行版本:先行版本也相同时,其优先级通过从左到右的每个被句点分隔的标识符来比较,直到找到差异值
- 数字标识符:按照数值的高低比较 (如:
1.0.0-alpha.5
>1.0.0-alpha.1
) - 字母:按照 ASCII 的顺序比较 (如:
1.0.0-alpha.rc
>1.0.0-alpha.beta
) - 正式版本相同时,非数字标识符优先级更高 (如:
1.0.0-alpha
>1.0.0-0
) - 先行标识符相同时,栏位较多的优先级更高 (如:
1.0.0-alpha.1.0
>1.0.0-alpha.1
)
- 数字标识符:按照数值的高低比较 (如:
- 正式版本:依次比较主版本号、次版本号、修订号,数字较大的优先级较高 (如:
这会阻碍快速开发和快速迭代吗
如果每天修改大量 API,那么应该继续使用
0.y.z
作为版本或者在单独的分支开发下一个主版本
如果意外地将向后不兼容的更改发布为次要版本,怎么办
- 一旦违反了语义化版本控制规范,请立即修复问题并发布新的次要版本,纠正问题并恢复向后兼容性
- 修改已发布的版本是不可接受的,如果合适,记录违规版本并告知用户
如果不改变公共 API,而是更新自身的依赖
- 理论上它不影响公共 API,但仍需明确引入的依赖具有其自身的依赖项规范,确定更改是补丁级别、修复错误、还是引入新功能
如果无意间以不符合的版本更改方式更改了公共 API (Breaking Changes)
- 如果更改对预期造成巨大影响,那么需要进行一次主要版本发布 (即使这该被视为补丁分布)
如何处理
已弃用的功能 (弃用的公共 API)- 更新文档,告知用户相关变更
- 发布包含弃用内容的新次要版本,在新的主要版本完全移除相关功能之前,应该至少发布一个包含启用内容的次要版本,方便用户过渡到新 API