不能只看composer.json的diff,因为它只声明“想要什么”,而composer.lock记录“实际装了什么”,包括隐式依赖的精确版本、dist.shasum、source.type和platform约束;例如monolog/monolog小版本升级可能引发psr/log从2.0.0升至3.0.0,触发bc break,但composer.json无变更。

为什么不能只看 composer.json 的 diff
只对比 composer.json 几乎必然漏掉真实风险。它只声明“想要什么”,而 composer.lock 记录“实际装了什么”——包括所有隐式依赖的精确版本、dist.shasum、source.type 和 platform 约束。比如 monolog/monolog 从 2.9.1 升到 2.9.2,composer.json 可能完全没动,但 composer.lock 里 psr/log 已悄悄从 2.0.0 变成 3.0.0,直接触发 BC break。
常见错误现象:
- PR 中
composer.json无变更,composer.lock却有数百行改动,reviewer 直接跳过 - CI 构建失败报
Class not found,本地却正常——实际是composer.lock里某个包的dist.shasum指向已下线 ZIP,或platform条件在 CI 环境不满足
用 composer-lock-diff 快速定位增删改
composer-lock-diff 是目前最轻量、最可读的锁文件比对工具,它把原始 JSON diff 转成人类能一眼看懂的摘要。
安装与基本用法:
- 全局安装:
composer global require clue/composer-lock-diff,确保~/.composer/vendor/bin在$PATH中 - 更新前备份:
cp composer.lock composer.lock.bak - 执行更新后运行:
composer-lock-diff composer.lock.bak composer.lock
输出示例:
ApiPost是一个支持团队协作,支持模拟POST、GET、PUT等常见请求,并可直接生成文档的API调试、管理工具,ApiPost是后台接口开发者或前端、接口测试人员的工作必备工具。快速生成、一键导出API文档。感兴趣的朋友快来下载吧。软件说明ApiPost官方版是一款十分出色的接口调试与文档生成工具,ApiPost官方版界面美观大方,功能强劲实用,支持团队协作,支持模拟POST、GET、PUT等常见请求,是后台接口开发者或前端、接口测试人员的工作必备工具。软件特色更方便支持接口调试的同时快速生成、一键
+ monolog/monolog 2.3.0 → 2.4.1 + guzzlehttp/guzzle (added) - phpunit/phpunit 9.5.10 (removed)
这个输出比 git diff 原始结果快 10 倍以上,且天然过滤掉格式缩进、字段顺序等噪音。
git diff 配合 grep 筛关键字段
如果无法安装额外工具,用 Git 原生命令也能高效抓重点。别扫全文件,聚焦四格缩进的变更行:
- 运行:
git diff --no-color HEAD~1 composer.lock | grep -E'^\+ {4}"(name|version|source|dist|type)' - 这条命令能精准捕获新增/修改的包名、版本、源类型(如
"type": "git")、dist 哈希值 - 特别注意:
"version": "dev-main"或"reference": "abc123"出现在 diff 中,必须追问是否真需指向不稳定分支或特定 commit - 若同一包名出现多个版本(如
symfony/event-dispatcher同时存在 6.3.2 和 7.0.0),说明 Composer 已做降级处理,要回溯composer.json中哪些require引入了冲突约束
审查时必须盯住的三个字段
composer.lock 不是配置文件,它是运行时快照。以下字段变动意味着行为可能已变,不能忽略:
-
content-hash:变了,说明依赖图真实不同;没变,大概率只是重生成(比如换 PHP 版本后composer install) -
platform区块:PHP 版本、扩展(如ext-redis)变化会直接影响运行时行为,尤其跨 major 版本升级时 -
packages和packages-dev下每个条目的dist.shasum:哈希不一致 = 安装内容不一致,哪怕版本号一样
最容易被忽略的是 packages-dev 区域——如果项目上线用 composer install --no-dev,这部分变动通常可跳过;但若上线流程漏了 --no-dev,这些开发依赖就会意外进入生产环境。










