最可靠方式是直接比对 composer.lock 文件,因 composer show 受终端宽度、排序及环境差异影响易误判,且未加 --locked 会混入非锁定状态包;应使用 --locked 导出 JSON 格式化后 diff,或借助 composer-lock-diff 聚焦关键变更。

直接比对 composer.lock 文件是最可靠的方式,其他方法(如 composer show)容易因排序、终端宽度或环境差异导致误判。
为什么不能用 composer show 直接对比
它输出受终端宽度、字母序、深度优先遍历顺序影响,两次执行结果可能不一致;composer show 查的是当前 vendor/ 状态 + composer.json 声明,会混入 path repo 或 dev-only 包,不是真实锁定快照。
常见错误现象:
-
composer show monolog/monolog在本地和 CI 上输出依赖顺序不同,diff显示大量“变化”,实际没变 -
composer show --tree未加--no-ansi,颜色控制符干扰文本比对 - 误用
composer show而非composer show --locked,比对对象错位
正确做法:
- 始终加
--locked:只读取composer.lock数据源,排除运行时干扰 - 导出为 JSON 并格式化:
composer show --locked --format=json | jq -S . > lock.json,再diff - 若只需看单包路径,用
composer show --tree --no-ansi vendor/package | sort,扁平化后可比
如何安全生成可复现的对比基线
关键不是“怎么 diff”,而是“怎么让两次输出结构完全一致”。任何手动修改、缓存残留、平台配置不一致都会污染结果。
必须检查的点:
-
config.platform是否两边一致?比如一边锁"php": "8.1.25",另一边是"8.2.0",composer.lock里packages数量和版本会系统性不同 - 是否都执行过
composer update --lock?本地若有未提交的composer.json修改但没更新 lock,会导致基线失真 - 生产环境是否用了
--no-scripts或--no-dev?这些参数不影响composer.lock内容,但会影响实际加载行为——比对 lock 只是第一步
推荐流程:
- 本地:运行
composer update --lock确保 lock 是最新解析结果 - 生产:从部署产物中提取原始
composer.lock(不要从运行中容器里cat,避免被临时修改) - 重命名备份:
mv composer.lock composer.lock.prod,再用diff -u composer.lock composer.lock.prod
用 composer-lock-diff 快速读出关键变更
它专为人类阅读设计,跳过 JSON 字段嵌套和哈希值噪音,聚焦增删改版本。
安装与使用:
- 全局安装:
composer global require clue/composer-lock-diff,确保~/.composer/vendor/bin在$PATH - 备份后执行:
composer-lock-diff composer.lock.bak composer.lock - Git 集成:
git show HEAD~1:composer.lock | composer-lock-diff - composer.lock
输出示例含义:
-
+ guzzlehttp/guzzle 7.5.0 → 7.8.1:升级,注意是否跨次要版本(7.x内通常安全) -
+ symfony/polyfill-mbstring (added):隐式引入,查composer why symfony/polyfill-mbstring确认来源 -
- phpunit/phpunit (removed):可能因--no-dev或依赖链收缩,确认是否影响测试流程
注意:composer-lock-diff 不校验哈希或源地址,仅比对 name/version/type,适合快速审计,不能替代二进制一致性验证。
哪些差异真正值得警惕
不是所有变更都需要人工介入。重点关注三类信号:
-
major版本跃迁(如monolog/monolog 2.9.0 → 3.0.0):查 CHANGELOG 里Breaking Changes小节,别只信composer outdated的!标记 - 同一包出现多个版本(
packages数组里有两条monolog/monolog记录):说明依赖树分裂,可能引发 autoloader 冲突或类加载歧义 -
dist.shasum改变但version不变:包作者重新发布了同版本 tarball(如修复文档),需确认是否引入了意料外的代码变更
最容易被忽略的一点:即使 composer.lock 里所有 version 字段都没变,packages 数组顺序或 require 子树结构也可能不同——这会影响 composer dump-autoload 生成的映射顺序,进而导致某些类在 CLI 和 Web SAPI 下行为不一致。











