composer.lock冲突不能手动解决,因其是依赖图快照而非普通配置文件;手动编辑会破坏JSON结构或哈希校验,导致install失败或静默装错包;正确做法是先合并composer.json,再删lock和vendor,运行composer update --no-install重建。

必须提交 composer.lock,所有环境统一执行 composer install —— 这不是建议,是底线。其他所有规范都围绕它展开。
为什么 composer.lock 冲突不能手动解决
它不是普通配置文件,而是整个依赖图的完整快照,含包顺序、哈希校验、嵌套依赖树结构。手动删 或凑合合并会直接破坏 JSON 合法性或 dist.sha256 校验值。
- 哪怕只改了一个空格,
composer install都可能报JSON decode error或静默跳过某些包 - 保留
--ours的 lock 却合并了对方的composer.json,会导致install失败或装出错误版本组合 - 用在线 JSON 工具“格式化”后合并,会触发大量因字段顺序/换行符差异导致的“假冲突”,掩盖真实变更
正确做法:先确保 composer.json 已合并完成(比如 git pull origin main),然后删掉本地 vendor/ 和 composer.lock,再运行 composer update --no-install 重建 lock 文件。
composer install 和 composer update 到底该谁用、什么时候用
日常开发中,95% 的场景只该用 composer install:它不解析版本,不联网,只按 composer.lock 精确安装,快且确定。
-
composer update是重算依赖树的操作,会修改composer.lock,甚至升级次要版本(如从2.8.1升到2.9.0),带来兼容性风险 - CI/CD 脚本里禁止出现
composer update,必须用composer install --no-interaction --no-progress - 升级依赖只能由专人操作:先
composer update vendor/package-name单独更新,跑全量测试,确认无误后再提交新composer.lock
如果 PR 合并后 CI 报 The lock file does not contain require-dev information,说明有人改了 composer.json 却没更新 lock —— 不是去修 lock,而是让提交者补跑 composer update 并提交。
如何防止 require 和 require-dev 混乱
放错位置不是小问题:把 phpunit/phpunit 放进 require,生产环境就多装几十 MB 无关代码;反过来把 guzzlehttp/guzzle 放进 require-dev,线上发 HTTP 请求直接失败。
-
require:仅放运行时真正需要的包(如monolog/monolog、guzzlehttp/guzzle) -
require-dev:只放开发/测试工具(如phpunit/phpunit、phpstan/phpstan) - CI 构建时加
--no-dev参数跳过 dev 包,减小镜像体积和攻击面 - 上线前用
composer show --dev快速核对,防止意外混入
更隐蔽的风险是 platform 配置缺失:composer.json 没写 "platform": {"php": "8.1.0"},本地 PHP 8.2 能跑,线上 PHP 8.1 就卡在 composer install 阶段失败 —— 这类问题往往等到部署才暴露。











