~1.2.3 允许安装 1.2.x 范围内所有版本,等价于 >=1.2.3

~1.2.3 到底允许装哪些版本?
它只放行 1.2.x 范围内的所有版本,等价于 >=1.2.3 。不是“差不多”,是硬性截断:哪怕 1.3.0 只改了一个文档 typo,也不会被接受。
-
~1.2.3→ 允许1.2.4、1.2.10、1.2.99,拒绝1.3.0和2.0.0 -
~1.2(省略 patch)→ 自动补为~1.2.0,即>=1.2.0 -
~1→ 补全为~1.0.0,即>=1.0.0 ,此时行为和^1.0.0重合,但语义不同:一个是“锁次版本锚点”,一个是“守主版本兼容”
什么时候必须用 ~,不能靠 ^?
当你依赖某个包的 次版本级行为细节,比如返回结构、钩子调用时机、配置项默认值在 1.2.x 和 1.3.x 之间有隐式差异,而测试只覆盖了 1.2.x 时,^1.2.3 可能悄悄升到 1.8.0,直接导致线上报错。
- 金融/支付类模块上线前要求人工验证每次 minor 升级 → 用
~1.2.3锁死分支 - 想跳过已知 bug 的小版本(如
monolog/monolog 2.7.5内存泄漏),又不想完全锁死失去后续 patch →~2.7.4比^2.7.4更可控 - CI 构建环境要求可重复、可审计 →
~提供更窄的升级窗口,降低非预期变更概率
0.x 版本下 ~ 和 ^ 的陷阱在哪?
两者都极度保守,但原因不同:^0.8.2 不是“宽松”,而是语义化版本强制降级为仅 patch 升级(>=0.8.2 );而 ~0.8.2 同样卡死在 0.8.x,但它的逻辑是“锚定最左侧非零段”,这里就是 8 所在的次版本位。
-
^0.8.2≡~0.8.2≡>=0.8.2 —— 表面写法不同,实际效果一致 - 但如果你写成
~0.8,它等价于~0.8.0,仍卡在0.8.x;而^0.8同样是>=0.8.0 - 真正危险的是误以为
^0.8.2能升到0.9.0—— 它不能,连0.8.3都要确认是否已发布且满足约束
怎么验证当前生效的约束范围?
别只看 composer.json 里写的符号,要看真实安装结果和更新行为。
- 查已装版本:
composer show monolog/monolog -i,显示的是vendor/下实际加载的版本 - 预览下次 update 会拉什么:
composer update --dry-run monolog/monolog,它按当前composer.json+composer.lock综合计算 - 快速定位谁阻止你升级:
composer prohibits monolog/monolog:2.8.0,能立刻告诉你哪个依赖硬性要求了更低版本 -
composer.lock必须提交进 Git —— 否则composer install会重新解析约束,结果不可控
最常被忽略的一点:约束符号只在 composer update 或首次 install 时起作用;一旦版本写进 composer.lock,符号就“失能”了——所以 lock 文件不是可选,是契约本身。











