不能用 git checkout --ours 解决 composer.lock 冲突,因其仅按行选取内容,会破坏 lock 文件与 composer.json 的强绑定关系,导致 require-dev 信息缺失、dev 包静默降级、字段顺序错乱等,进而引发 install 失败或运行时异常;唯一安全做法是以 clean 合并后的 composer.json 为唯一源,执行 composer update --lock 重建快照。

composer.lock 冲突不能手动解决,必须丢弃并重建;它不是配置文件,是依赖图的哈希快照,任何文本级“合并”都会破坏 content-hash 或 JSON 合法性,导致 install 失败或静默装错包。
为什么不能用 git checkout --ours 解决 composer.lock 冲突
Git 的 --ours 或 --theirs 是按行选内容,但 composer.lock 里每个包的 dist.sha256、content-hash、packages 数组顺序都和 composer.json 全局状态强绑定。选错后:
- 保留 A 分支的
laravel/frameworkv10.42.0,但 B 分支新增的spatie/laravel-ray在packages-dev里没被写入 →composer install报The lock file does not contain require-dev information - 选了
--theirs的 lock,但本地composer.json已删掉phpunit/phpunit→ install 不报错,却悄悄装出旧版 dev 包,CI 通过但本地跑不起来 - 字段顺序被 Git 自动重排(比如
name和version调换)→composer validate通过,但后续composer update --lock会重写整块,掩盖真实变更
冲突发生后唯一安全的重建流程
核心是放弃 lock 文件本身,以合并后的 composer.json 为唯一可信源,让 Composer 重新生成。
- 先确保
composer.json已 clean merge:运行git merge origin/main或git rebase origin/main,手动解决其中增删改(如确认"monolog/monolog": "^3.0"是否该保留) - 删掉本地
vendor/和composer.lock(避免残留干扰) - 运行
composer update --no-install:只更新 lock,不重装 vendor;检查输出里是否有意外downloading行(比如guzzlehttp/psr7从 2.6.2 降级到 2.5.0) - 确认无误后
git add composer.lock,提交时附带明确描述,例如:lock: sync monolog ^2→^3 + php 8.3 platform constraint
怎么让 composer.lock 变更只改几行、减少假冲突
Git 标红 composer.lock 不代表依赖变了,大概率是排序或空格差异。关键在统一生成规则:
- 所有成员执行
composer config -g sort-packages true,让packages和packages-dev按字母序固定排列 - 禁用裸
composer update:只允许composer update vendor/package-name --with-dependencies,避免全量重排触发大面积 diff - CI 中加校验步骤:
composer install --dry-run,失败即阻断 PR 合并——说明有人改了composer.json却没提交新 lock
composer update --lock 和 composer install 的本质区别
composer install 是“按 lock 装”,要求 lock 文件本身合法且与当前 composer.json 匹配;而 composer update --lock 是“按 json 重算 lock”,不读旧 lock,只基于当前 composer.json 生成全新合法快照——这才是冲突场景下唯一安全动作。
- 运行前必须确保
composer.json已无冲突(可用git checkout --theirs composer.json或手动整合) - 删掉当前冲突的
composer.lock(或先mv composer.lock composer.lock.bak) - 运行
composer update --lock,预期输出应为:Lock file operations: 0 installs, 0 updates, 0 removals;如果出现大量Updating xxx,说明composer.json还没拉齐
真正难的不是命令怎么敲,而是所有人对“谁来决定依赖版本”这件事达成共识——composer.json 是契约,composer.lock 是快照,vendor/ 是结果。三者链条断一环,环境就不一致。


















