跳到内容

第 0 卷 / 第 5 章 / 第 3 课

5.3 语义化版本、范围与冲突 ​

前置知识:Maven 基础

预计时间:15 分钟

完成标志:能解释 SemVer,并避免把 npm 范围语法套到其他生态

清单终于写好了,但 ^1.2.3、~=1.4.2 和 [1.0,2.0) 看起来都像“允许某个范围”。先停一下:版本号的含义与解析器的范围语法是两层规则,不能凭长相互换。

SemVer 描述公共 API 变化 ​

在发布者遵守 Semantic Versioning 2.0.0 的前提下:

版本段何时增加
MAJOR公共 API 出现不兼容变化
MINOR增加向后兼容功能,或标记公共 API 为废弃
PATCH修复向后兼容的错误

0.y.z 用于初始开发,公共 API 不应视为稳定。预发布版本低于对应正式版;+build 元数据不参与优先级比较。版本号表达的是发布者承诺,不能代替变更说明和测试。

npm 的 caret 和 tilde ​

json
{
  "dependencies": {
    "stable-api": "^1.2.3",
    "zero-minor-api": "^0.2.3",
    "patch-line": "~1.2.3"
  }
}
写法npm 范围
^1.2.3>=1.2.3 <2.0.0
^0.2.3>=0.2.3 <0.3.0
^0.0.3>=0.0.3 <0.0.4
~1.2.3>=1.2.3 <1.3.0
1.2.3精确匹配

表格按普通正式版描述范围;预发布版本还有额外的匹配规则,并非只比较上下界就会自动纳入。上面的包名仅为配置示意,不要求安装,参见 node-semver 的范围与预发布规则。

caret 范围在 0.x 下更窄:^0.2.3 的上界是 0.3.0,^0.0.3 的上界是 0.0.4,均不包含上界。确定范围时,要检查最左侧的非零版本分量。

Python 使用 PEP 440 说明符,如 >=1.2,<2、~=1.4.2;Maven 范围写作 [1.0,2.0)。三套语法不能互换。

冲突并不都靠“装两份”解决 ​

  • Maven 通常使用最近定义;同深度时先声明者优先。dependencyManagement 能管理版本,但不会自动引入依赖。
  • npm 可以在依赖树不同位置保留多个版本,peer dependency 仍可能冲突。
  • pip 在一个虚拟环境中通常只能为某个分发包安装一个版本,约束无解时应失败。
  • Gradle 的选择受 configuration、约束、平台、规则和锁定设置影响。

查看原因:

bash
npm explain PACKAGE_NAME
npm ls --all
./mvnw dependency:tree
./gradlew dependencyInsight --dependency NAME --configuration runtimeClasspath
python -m pip check

排除传递依赖前,先确认最终运行时 classpath 和兼容要求。exclusion 可能把必需类一并移走。

离开这一页前 ​

看到 ^0.2.3,先写出上界 <0.3.0;看到两个 Maven 路径选中不同版本,再检查深度、声明顺序和 dependencyManagement。最后给候选升级补上兼容性测试。lock 固定的是解析结果,无法替你检验行为。

→ 下一步:综合实验

Built with VitePress | Software Systems Atlas