简述

SemVer 是 Semantic Versioning (语义化版本控制)的简称,中文通常叫做语义化版本号

其核心思想是:

版本号不仅仅是一个编号,还要表达与上一个版本之间的兼容关系

形象点说就是当你看到一个版本号从 1.1.0变成了 1.2.0,你就大概知道这是添加了新功能;看到从 1.2.0变成了 2.0.0,你就大概知道这是进行了一些破坏性更新,可能不会兼容之前的版本

基本

格式

基本版本格式

最基本格式:

X.Y.Z

对应

X -> MAJOR(主版本号)
Y -> MINOR(次版本号)
Z -> PATCH(修订号)

要求:

  • 必须由三个数字组成
  • 三个数字之间用英文句点 . 分隔
  • 数字表示非负整数
  • 不能有前导零(例如 1.02.301.0.0 是不合法的)
  • 每个元素必须数值递增(例如 1.9.0 -> 1.10.0 -> 1.11.0

例如:

1.0.0
2.3.4
10.20.30

注意:0.y.z 版本用于初始开发阶段,任何内容都可能随时变化,公共 API 不应被视为稳定。1.0.0 才正式定义了公共 API

先行版本格式

先行版本,也叫预发布版本(prerelease

格式是在 X.Y.Z 后面加 -

X.Y.Z-prerelease

例如:

1.0.0-alpha
1.0.0-alpha.1
1.0.0-beta
1.0.0-rc.1

要求:

  • 用英文句点 . 分隔
  • 每个标识符只能包含:
    • ASCII 字母:A-Za-z
    • 数字:0-9
    • 连接号:-
  • 不能有空白字符
  • 数字型标识符不能有前导零

优先级:

1.0.0-alpha < 1.0.0

先行版本的优先级低于对应的正式版本

当两个先行版本具有相同的主版本号、次版本号和修订号时,优先级按照以下规则从左到右逐个标识符比较:

  1. 纯数字标识符按数值大小比较(例如 2 < 11
  2. 包含字母或连字符的标识符按 ASCII 字典序比较
  3. 数字标识符的优先级总是低于非数字标识符
  4. 如果前面的标识符都相同,拥有更多字段的版本优先级更高

例如:

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

实际项目中你不一定需要记这么细,但要知道

alpha < beta < rc < 正式版

常见标识:

标识 含义 形象解释
alpha 内测版 早期、不稳定
beta 公测版 功能基本完成但可能有 bug
rc Release Candidate,候选发布版 功能完成且没有明显 bug
dev 开发版
snapshot 快照版

一个版本可能会这样迭代:

1.0.0-alpha.1
1.0.0-alpha.2
1.0.0-beta.1
1.0.0-beta.2
1.0.0-rc.1
1.0.0-rc.2
1.0.0

构建信息格式

构建信息( build metadata),格式是在 X.Y.Z 后面加 +

X.Y.Z+build

或者在 prerelease 后面加:

X.Y.Z-prerelease+build

例如:

1.0.0+20260101045141
1.0.0+build.123
1.0.0+git.abc123
1.0.0-alpha+001
1.0.0-beta+exp.sha.5114f85

要求:

  • 用英文句点 . 分隔
  • 每个标识符只能包含:
    • ASCII 字母:A-Za-z
    • 数字:0-9
    • 连接号:-
  • 不能有空白字符

优先级:

构建信息不影响版本优先级,也就是说

1.0.0+build.1

1.0.0+build.2

在版本优先级上相同

构建元信息用于记录构建相关的信息。例如 1.1.4+build.514 表示这是 1.1.4 版本的第 514 次构建,1.1.4+20260514 表示该版本于 20260514 构建,1.1.4+git.abc5141 表示该版本由 Git commit abc5141 构建而来

当然这些都不是强制语义,只是约定。SemVer 标准只规定了 + 的后面是 build metadata,具体的命名规则由你的团队、构建系统自行定义。常见的有 git.xxxsha.xxxcommit.xxx(通常表示 Git commit hash)、build.xxxci.xxx

完整格式

完整格式为:

X.Y.Z-prerelease+build

例如:

1.2.3-alpha.1+build.456

拆开就是:

版本号 解释
1.2.3 标准版本号
-alpha.1 先行版本号
+build.456 构建信息

迭代规则

PATCH

PATCH 表示修订号,当你做了向后兼容的问题修正时,递增 PATCH(前提是主版本号 x > 0):

1.2.3 -> 1.2.4

常见情况:

  • 修复了若干 bug
  • 修复安全漏洞
  • 修复兼容性问题
  • 重构了代码但既没有添加新功能也没有进行破坏性变更
  • ......

MINOR

MINOR 表示次版本号,当你做了向后兼容的新功能或将公共 API 中的功能标记为**弃用(deprecated)**时,递增 MINOR(前提是主版本号 x > 0):

1.2.3 -> 1.3.0

MINOR 递增时,PATCH 需归零

比如 1.2.3 要进行次版本号迭代,那么应该是:

1.2.3 -> 1.3.0 (PATCH归零)

而不是

1.2.3 -> 1.3.3 (PATCH没有归零,这是错的)

常见情况:

  • 新增配置项
  • 新增 API
  • 新增功能
  • 将公共 API 中的功能标记为弃用(deprecated)
  • 优化性能但不改变程序行为
  • ......

MAJOR

MAJOR 表示主版本号,当你对公共 API 做了不兼容的修改时,递增 MAJOR:

1.2.3 -> 2.0.0

MAJOR 递增时,PATCH 和 MINOR 需归零

比如 1.2.3 进行了不兼容的修改:

1.2.3 -> 2.0.0 (MINOR和PATCH都归零)

而不是

1.2.3 -> 2.2.3 (MINOR和PATCH没有归零,这是错误的)

常见情况:

  • 协议不兼容
  • 配置文件格式变动
  • 用户升级后必须修改配置
  • 数据格式变动
  • ......

此外,已发布的版本内容不可修改,任何修改都必须作为新版本发布

兼容

SemVer 最重要的不是数字本身,而是兼容性承诺

向后兼容

向后兼容,也叫 backward compatible。意思是用户原来基于旧版本写的代码,在最新版本依然可以正常工作

例如旧版本支持:

sum(1, 2)

在新版本仍然支持这样写。与此同时增加了新能力:

sum([1, 2, 3])

旧代码也可以按照旧版本的方式使用,这就是向后兼容。升级 MINOR

不兼容变更

不兼容变更,也叫 breaking change 或者破坏性变更。意思是用户升级后,原来的代码、配置、数据、命令可能不能直接用了

例如旧版本是这样的:

login(username, password)

而新版本改成了这样:

signIn(username, password)

这就是不兼容变更,应该迭代 MAJOR

除此之外,这些也叫不兼容变更

  1. 改变默认行为

    假如旧版本默认 自动重试 3 次,而新版本默认 不自动重试。即使 API 没变,但行为变了也算是不兼容变更

  2. 修改返回值结构

    旧版本:

    {
      "id": 1,
      "name": "huajibenji"
    }
    

    新版本:

    {
      "userId": 1,
      "displayName": "huajibenji"
    }
    

    旧代码可能依然会读取 idname,所以这是不兼容变更

  3. 修改参数顺序

    旧版本:

    createUser(name, age)
    

    新版本:

    createUser(age, name)
    

    旧代码可能依然会按照 name, age的顺序进行读取,所以这也是不兼容变更

实践

依赖管理中的 SemVer

SemVer 在管理器里非常重要,常见的有:

  • npm
  • pnpm
  • Cargo
  • yarn
  • ......

以 npm 为例,我们经常可以在依赖中看到:

{
  "dependencies": {
    "lodash": "^4.17.21",
    "axios": "~1.6.0"
  }
}

你可能会问,这里的 ^~是什么意思?别急,下面会讲

精准匹配版本

比如这样:

"axios": "1.6.0"

表示只安装 1.6.0 这个版本

~ 波浪号范围

"axios": "~1.6.0"

表示允许 PATCH 升级:

>=1.6.0 <1.7.0

也就是可以安装:

1.6.1
1.6.2
1.6.9

但是不会安装

1.7.0
2.0.0

^ 脱字符范围

这样:

"axios": "^1.6.0"

表示不允许破坏性更新。对于 1.6.0 ,等价于

>=1.6.0 <2.0.0

也就是可以安装

1.6.1
1.7.0
1.8.5

但是不会安装

2.0.0

因为按照 SemVer,1.x.x 范围内的 MINOR 和 PATCH 都应该兼容

^0.x 版本中的表现可能会不太一样

因为 0.x 表示不稳定,所以 ^0.x 中更保守。例如

"some-lib": "^0.2.3"

通常等价于:

>=0.2.3 <0.3.0

也就是说不会自动升级到大于等于 0.3.0 的版本,因为在此以上的版本都可能会有不兼容的变更

SemVer 和 Changelog

SemVer 最好配合 CHANGE LOG 使用,比如:

## 1.3.0 - 2026-07-09

### Added
- 新增用户导出功能
- 新增 CSV 格式支持

### Fixed
- 修复分页参数为 0 时崩溃的问题

### Deprecated
- 标记 `getUserInfo` 为废弃,建议使用 `getUser`

## 1.2.1 - 2026-06-20

### Fixed
- 修复登录 token 刷新失败的问题

常见分类:

分类 含义
Added 新增功能
Changed 修改已有行为
Deprecated 标记废弃
Removed 删除功能
Fixed 修复问题
Security 安全修复

如果有不兼容变更,应该明确写:

### Breaking Changes
- 删除 `login(username, password)`,请改用 `signIn({ username, password })`

Deprecated:废弃但不删除

在 SemVer 中,如果你想移除一个 API,最好不要马上就删。一般推荐的流程是:

1.2.0   标记旧 API 为 deprecated,但仍然可用
1.3.0   继续提醒用户迁移
2.0.0   删除旧 API

这样可以给足用户迁移的时间

0.x 版本的特殊含义

这通常表示项目处于初始开发阶段,比如:

0.1.0
0.1.4
0.5.14
0.9.0

0.x 阶段,项目通常还没承诺稳定兼容。例如:

0.3.0 → 0.4.0

这看起来好像只是一个 MINOR 变化,但是这也可能包含不兼容变更

一般情况下,一个项目迭代到 1.0.0 版本才表示这个项目已经有稳定的公共 API,可以用于生产或正式使用

一般情况下,项目一般都会从 0.1.0 开始迭代

常见问题

Q & A

一般什么时候发 1.0.0

通常满足这些条件就可以发 1.0.0

  • 核心功能已经完整
  • API 基本稳定
  • 文档比较完整
  • 测试覆盖较好
  • 已经有人或生产环境使用
  • 后续会认真遵守兼容性规则
  • 不希望随意破坏用户使用方式

v1.x.x算是 SemVer 吗?

不算。但是,在语义化版本号之前增加前缀 v 是用来表示版本号的常用做法

在版本控制系统中,将 version 缩写为 v 是很常见的,比如:

git tag v1.2.3 -m "Release version 1.2.3"

v1.2.3 表示标签名称,而 1.2.3 是语义化版本号

引用自semver.org

prerelease 是怎么迭代的?

比如 1.0.0-alpha.1 -> 1.0.0-alpha.2 算版本迭代吗?

算,虽然 1.0.0 没变,但完整版本号已经变了:

1.0.0-alpha.1
1.0.0-alpha.2

所以它们是两个不同的版本。根据 SemVer 规则:

1.0.0-alpha.1 < 1.0.0-alpha.2 < 1.0.0

你可能会问:代码变了,为什么不一定要改 X.Y.Z

因为 prerelease 部分本身就是版本号的一部分。

1.0.0-alpha.1

可以理解为:

1.0.0 正式版发布前的第一个 alpha 版本

1.0.0-alpha.2

可以理解为:

1.0.0 正式版发布前的第二个 alpha 版本。

所以只要完整版本号变化了,就已经是新版本,不一定必须改 X.Y.Z

一句话总结就是:1.0.0-alpha.11.0.0-alpha.2 是两个不同的版本,虽然它们的目标正式版都是 1.0.0,但它们是两个不同的 prerelease 版本

[!IMPORTANT]

个人理解,此处仅供参考。因为官方没有定义过 prerelease 的迭代

1.0.0-alpha -> 1.0.1-alpha 合法吗?

合法,但语义变了:

1.0.0-alpha

表示 1.0.0 的预发布版本

1.0.1-alpha

表示 1.0.1 的预发布版本

所以这不是同一个正式版本的 prerelease 迭代,而是目标正式版本从 1.0.0 变成了 1.0.1

alpha、beta、rc 是 SemVer 强制要求的吗?

不是。SemVer 只规定 prerelease 的格式和排序规则,不强制使用 alphabetarc

这块内容 更多取决于项目或者个人的规定

常见误区

版本号是小数

很多人会误以为

1.10.0 < 1.9.0

因为按小数看 1.10 等于 1.1

实则不然,版本号不是小数,而是多个整数段

这点在 SemVer 官方文档中也讲到过

咕咕嘎嘎🐧🐧