composer.lock是依赖图的哈希快照,非配置文件,记录精确版本、dist URL、校验和等,手动编辑极危险;Git合并冲突时应弃用手工合并,改用git checkout --ours/--theirs恢复后重装。

composer.lock 是快照,不是配置文件
它记录的是整个依赖图的哈希、版本、dist URL 和校验和,不是人该手动改的东西。Git 合并时标出的 composer install 很可能直接失败,报 Your lock file does not contain a compatible set of packages——因为快照被撕裂了。
常见错误现象:
- 手动保留“这边的 monolog 版本”+“那边的 guzzle commit hash”,结果 vendor 里装出来两个包不兼容
- 删掉冲突标记后直接
composer install,但require-dev包没参与解析,CI 跑不过 - 以为
--no-dev就能绕过 dev 包影响,其实从 Composer 1.7 起,require-dev的约束全程参与依赖树求解
冲突发生时,先确认 composer.json 是否干净
如果 composer.json 本身也有 Git 冲突,别碰 composer.lock —— 先 resolve composer.json,否则所有后续操作都在错的基础上叠加错误。
实操建议:
- 运行
git status,只看到composer.lock冲突?可以继续 - 看到
composer.json也冲突?先手工合并它,确保所有require和require-dev条目都整合正确 - 再跑
composer validate,确认语法和字段合法;若报lock file has some errors,说明已损坏,跳过手动修复,直接重建
重建 lock 文件的三步稳态流程
不用猜哪边该留,也不用比对 diff,靠 Composer 自己重算最可靠。
步骤如下:
- 删掉当前
composer.lock和vendor/目录(确保无残留) - 运行
composer update --lock(注意不是install),它会基于当前composer.json重新生成完整快照,同时校验平台约束(PHP 版本、扩展等) - 提交新的
composer.lock—— 此时它反映的是合并后的真实依赖状态,不是某一分支的“记忆”
这个流程能自动处理 require-dev 约束、PHP 平台要求、甚至 repositories 配置带来的镜像覆盖逻辑,比任何手动 patch 都准。
团队协作中真正要防的不是冲突,是“谁在什么时候动了 lock”
冲突只是表象,根因常是协作节奏混乱:有人在 feature 分支狂 composer update,有人在主干刚锁死一套版本,一合并就炸。
可落地的预防点:
- 功能分支里只用
composer require xxx或composer remove xxx,它们会自动更新composer.lock,且变更集中、语义清晰 - 合入主干前,在 feature 分支上跑一次
composer update --lock,让 lock 哈希与主干对齐,减少 merge 时的 JSON 结构差异 - 在项目根目录加
.gitattributes,写composer.lock merge=ours,避免 Git 默认文本合并策略产出非法 JSON(CI 失败十次有八次是这原因)
最易被忽略的一点:composer.lock 一旦被破坏,composer install 就不再是“还原环境”,而会退化成隐式 update,结果完全不可控——所以别省那几秒,该删就删,该重生成就重生成。











