语义化版本
语义化版本 是一个常见的术语,相信大部分人都或多或少听过。可能与大部分人不同,我在了解语义化版本后,摆脱了刀耕火种的道路,走上了遵循规范、约定式优先的开发道路。因此,语义化版本对我有着特殊的意义。
什么是语义化版本
简而言之,语义化版本是用于解决版本号混乱的方案。它定义了一组规则,来控制版本号的变化。
基本格式
最基本的语义化版本格式如下:
主版本号.次版本号.修订号
major.minor.patch
X.Y.Z
- X 会在破坏性更新时 +1,此时会将 Y 和 Z 重置为 0。
- Y 会在新增向下兼容的功能性时 +1,此时会将 Z 重置为 0。
- Z 会在修正向下兼容的问题时 +1。
当然,语义化版本也充分考虑了先行版本号和编译信息的问题。这不是这篇博客的重点,如果你感兴趣,可以点进博客开头的链接,阅读完整的文档。
为什么要用语义化版本
一方面,语义化版本方便了别人。用户无需特别翻看改动日志,从版本号的变化就能直观地了解是否存在破坏性更新。
另一方面,语义化版本方便了自己。你可以使用大量支持语义化版本的工具和库来开发和管理自己的工具和库。比起非语义化版本,你可以省去大量的时间。
更何况,语义化版本已经被广泛采用。打不过就加入是一个经验之谈(笑)。
谁在用语义化版本
正如前面所说的,语义化版本已经被广泛采用。npm
、webpack
、vite
、rollup
、antd
等库就是遵循语义化版本的巨头。
语义化版本的缺陷
语义化版本是理想化的,版本号的变动实际上反映的是开发者的预想。实际上,修复一个问题或者新增一个功能,引出了另一个问题,这并不少见。
另外,npm
生态内也出现过通过语义化版本投毒的情况。比如 ^2.0.0
允许主版本号为 2 的所有版本,如果在 2.0.1
版本投毒,用户是有可能中招的。这就只能锁定版本,在更新前检查依赖,这种信任问题需要付出额外的时间和精力来避免,实际上抹去了语义化版本的优势。
其它的版本号方案
Android 的版本号 Version Code
实际上就是一个正整数,每次发布新版本只需直接 +1,而版本名 Version Name
可以遵循语义化版本。
Jetbrains 家的产品使用年份、月份和编译信息作为版本号。
某些项目看着遵循语义化版本,但实际上并非如此,具体还是要根据官方表达为准。
实践
在 npm
生态中,有很多工具可以帮你实践语义化版本。
我最初使用的是 np。这是一个简单的工具,在大部分场景下,它工作得很好。
在社区切换到 pnpm
的风潮之下,我也尝试了一下 pnpm
,发现 pnpm
用起来非常舒服,打算切换到 pnpm
。遗憾的是,我发现 np
对 pnpm
支持不是太好。所以,我转向使用另一个包 release-it。
release-it
在大部分时间工作得很好,它也能支持 monorepo
,就是需要手动配置一下。但我不是太喜欢它先 publish
到 npm
仓库再 push
到 git
仓库的行为,所以我转向使用 bumpp。
bumpp
非常轻量,只负责更新版本,不负责推测下一个语义化版本应该是什么,也不负责生成改动日志。我更喜欢使用一体化的方案,所以我后续又转向使用 commit-and-tag-version。