2. 语义化版本规范(SemVer)详解

版本号这东西,看着简单,但坑特别多。我刚入行那会儿,团队里就因为没有统一的版本规范,出现过好几次「这个版本到底能不能用」的尴尬场面。后来我们全面推行了语义化版本规范(SemVer),才算是把版本管理这件事理清楚了。

说白了,SemVer 就是一套版本号的「交通规则」。它告诉你什么时候该升主版本,什么时候改次版本,什么时候打补丁。规则清晰了,大家协作起来就顺畅多了。

2.1 版本号的三段式结构

语义化版本号长这样:主版本号.次版本号.补丁号。比如 1.4.2,意思就是主版本 1,次版本 4,补丁 2。

这三段数字,每一段都有明确的含义:

组成部分 英文名 含义 什么时候递增
主版本号 MAJOR 不兼容的 API 变更 做了破坏性修改时
次版本号 MINOR 向下兼容的功能新增 加了新功能,且不影响旧代码
补丁号 PATCH 向下兼容的问题修复 修了 bug,没加新功能

举个例子你就明白了。假设你用的是 2.3.1 版本的某个库:

  • 如果升级到 2.3.2,说明只是修了个小 bug,放心升。
  • 如果升级到 2.4.0,说明加了新功能,但旧代码还能跑。
  • 如果升级到 3.0.0,那就要小心了——API 可能变了,你的代码很可能要改。

核心原则:版本号不仅仅是数字,它是在向使用者传递信息。每次变更,都要问自己一句:「这个改动会不会让别人的代码跑不起来?」

2.2 预发布版本

有时候你开发了一个新版本,但还没完全稳定,想先放出来让大家试试。这时候就需要预发布版本。

预发布版本号是在标准版本号后面加一个连字符,然后跟上标识符。比如 1.0.0-alpha.1、2.0.0-beta.2、3.0.0-rc.1。

常见的预发布标识符有:

  • alpha:内部测试版,功能可能不全,bug 很多。
  • beta:公开测试版,功能基本完整,但还有已知问题。
  • rc:发布候选版,基本稳定了,只差最后验证。

我个人习惯在项目进入 beta 阶段后,才开始对外发布预发布版本。alpha 阶段太早期了,放出去反而容易让用户困惑。

小技巧:预发布版本的优先级低于正式版本。比如 1.0.0-alpha 的优先级低于 1.0.0。这意味着如果你依赖了 ^1.0.0,npm 不会自动安装 1.0.0-alpha 版本。

2.3 构建元数据

构建元数据是版本号里最容易被忽略的部分。它用加号 + 跟在版本号后面,用来记录构建相关的信息。

比如 1.0.0+build.20240315 或者 2.3.1+sha.7a9f3d2。构建元数据不影响版本优先级,它只是附加信息。

构建元数据通常包含:

  • 构建时间戳
  • Git 提交哈希
  • CI 构建编号
  • 编译环境信息

我记得有一次线上出了个诡异的问题,排查了半天才发现是构建环境不一致导致的。后来我们在版本号里加上了构建元数据,每次发布都能追溯到具体的构建记录,排查效率高了很多。

注意:构建元数据不会被版本比较器考虑。也就是说 1.0.0+build.1 和 1.0.0+build.2 在语义上被认为是同一个版本。所以不要用构建元数据来做版本区分,它只是「备注」。

2.4 版本优先级规则

版本号之间怎么比较大小?SemVer 有一套明确的规则:

  1. 先比较主版本号,大的优先级高。
  2. 主版本号相同,比较次版本号。
  3. 主次都相同,比较补丁号。
  4. 正式版本优先级高于任何预发布版本。
  5. 预发布版本之间,按标识符逐段比较。

举个例子:

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

你想想看,如果没有这套规则,两个版本号摆在你面前,你根本不知道哪个更新。有了优先级规则,依赖管理工具才能自动判断要不要升级。

2.5 实战中的避坑指南

我在项目中遇到过不少版本号相关的坑,挑几个典型的说说:

  • 不要随意改主版本号。我曾经见过一个项目,每次发布都升主版本号,结果版本号从 1.0.0 一路飙到 47.0.0。这完全失去了语义化的意义。
  • 预发布版本不要用在生产环境。除非你明确知道自己在做什么,否则别把 alpha、beta 版本部署到线上。
  • 构建元数据不要包含敏感信息。比如内网 IP、密钥之类的,这些信息会随着版本号暴露出去。

一句话总结:版本号是沟通工具,不是装饰品。每次改版本号,都要让下游开发者能看懂你的意图。

2.6 知识结构图

下面这张图帮你理清 SemVer 的整体结构:

语义化版本号 主版本号 (MAJOR) 次版本号 (MINOR) 补丁号 (PATCH) 不兼容的 API 变更 向下兼容的新功能 向下兼容的 bug 修复 预发布版本 (如 -alpha, -beta, -rc) 构建元数据 (如 +build.20240315)

嗯,到这里语义化版本规范的核心内容就讲完了。下一章我们会聊聊在实际项目中,如何用 SemVer 来管理依赖版本,以及常见的版本范围表达式该怎么写。