语义化版本¶
语义化版本(Semantic Versioning,简称 SemVer) 是一种软件版本号的命名规范,由 Tom Preston-Werner 于 2011 年提出,现在已被广泛应用于开源社区(如 npm、Cargo、Composer、PyPI 等)和现代软件开发流程中。
其核心思想是:通过版本号本身传达变更的含义,让开发者清楚地知道升级某个版本可能会带来什么影响。
版本格式¶
标准的语义化版本格式为:
MAJOR.MINOR.PATCH[-预发布标识][+构建元数据]
例如:
-
2.3.1 -
1.0.0-alpha.1 -
3.1.4-beta.2+build.20250512
各部分的含义¶
| 部分 | 含义 | 何时递增 | 对兼容性的影响 |
|---|---|---|---|
| MAJOR (主版本) | 引入了不兼容的 API 变更 | 当有破坏性改动(Breaking Change)时 | 不兼容 |
| MINOR (次版本) | 增加了向下兼容的新功能 | 新增特性,但不破坏现有功能 | 兼容 |
| PATCH (修订版) | 进行了向下兼容的 bug 修复 | 只修复 bug,不改变 API | 兼容 |
预发布标识(Pre-release):如 -alpha.1、-beta.2、-rc.3,表示该版本不稳定,可能存在 bug,不建议在生产环境使用。
构建元数据(Build metadata):如 +build.123、+sha.abc123,通常用于 CI/CD 构建信息,不影响版本比较。
版本比较规则¶
-
1.0.0 与 2.0.0 不兼容
-
1.2.3 与 1.3.0 兼容(新增功能)
-
1.2.3 与 1.2.4 兼容(bug 修复)
-
预发布版本总是低于对应的正式版本(例如
1.0.0-alpha < 1.0.0)
常见约定¶
-
0.y.z 版本(主版本为 0):表示初始开发阶段,API 可能随时发生不兼容变更。
-
1.0.0 通常标志着第一个稳定版本。
-
公开 API:只有对外公开的接口才需要遵循语义化版本,内部实现变更不一定要递增 MAJOR。
-
^ 和 ~ 的含义(常见于 package.json):
-
^1.2.3=>=1.2.3 <2.0.0(允许 MINOR 和 PATCH 升级) -
~1.2.3=>=1.2.3 <1.3.0(只允许 PATCH 升级)
优点¶
-
清晰传达变更影响
-
便于自动化依赖管理(例如 Dependabot、npm 等)
-
降低升级风险
-
促进团队和生态系统形成统一的版本沟通语言
实际例子¶
-
React 从
0.x升级到16.0.0、17.0.0、18.0.0时都进行了重大变更,因此主版本递增。 -
Linux 内核使用的是自己的版本方案,但很多周边工具(如 Docker、Kubernetes)都严格遵循 SemVer。
更新项目元数据、文档、构建流水线等是否需要迭代修订号?¶
不是严格只修改源码才迭代修订号(PATCH),但核心原则是围绕“向下兼容的 bug 修复”。
-
PATCH 版本(修订号)MUST 在只引入向下兼容的 bug 修复时递增。
-
Bug fix 的定义:一个内部变更,用于修正不正确的行为(internal change that fixes incorrect behavior)。
这意味着:
-
主要针对代码中的错误修复(修复 bug、崩溃、安全漏洞、性能问题等),且不改变公共 API 的行为。
-
只要是修复“错误行为”,即使涉及源码修改,也用 PATCH。
因此一般不需要专门为这些更新递增 PATCH,但实际处理有以下常见做法:
-
纯文档更新(README、注释、示例代码、文档网站等):
-
如果只是修正错别字、格式、澄清说明,通常不需要版本迭代,或者只作为补丁发布(很多人会用 PATCH)。
-
如果文档是公共 API 声明的一部分(例如 API 文档与实际行为不符),修正它本质上是“修复不正确行为”,可以视为 bug fix,用 PATCH。
-
-
构建流水线、CI/CD 配置、项目元数据(package.json 中的描述、作者信息等):
-
这些通常不影响公共 API,也不属于“修复不正确的运行时行为”。
-
常见处理方式:
-
不递增版本,直接在当前版本上更新(尤其是内部工具或私有项目)。
-
如果必须发布新包/镜像,则递增 PATCH(视为维护性改进)。
-
有些项目会用构建元数据(+build.xxx)来区分,而不改变核心版本号。
-
-
-
核心原则:版本号是为使用者服务的。问自己:“这个变更是否会让依赖我包的用户感到意外?”
-
纯文档/流水线变更 → 用户通常感受不到 → 可以不 bump 或用 PATCH。
-
修复了实际 bug(即使是文档描述的错误行为)→ 用 PATCH。
-
-
推荐做法:
-
维护 CHANGELOG.md,清楚标注每一项变更属于哪类。
-
使用自动化工具(如 semantic-release + Conventional Commits),通过 commit 消息自动决定版本类型(fix: → PATCH)。
-
小型变更可以积累几个后再统一发布一个 PATCH 版本,避免版本号碎片化。
-
修订号(PATCH)主要为代码 bug 修复准备,但文档和构建变更通常用 PATCH 发布或不单独发布,具体取决于是否需要让下游用户拉取新版本。规范更关注“公共 API 的实际行为是否正确”,而不是严格区分“改没改源码”。