因为 composer.lock 精确记录依赖树、版本哈希、安装路径和平台约束,随意选一边会导致依赖不一致、子依赖降级或运行时错误。应通过 composer update --lock 重生成,而非手动修改或依赖 Git 文本合并。

为什么 composer.lock 合并冲突不能随便选一边?
因为 composer.lock 不是普通配置文件,它精确记录了每个包的完整依赖树、版本哈希、安装路径和平台约束。如果合并时粗暴保留某一方,很可能导致:
• 本地 composer install 安装出和 CI 或其他开发者不一致的依赖
• 某个包的子依赖被意外降级或跳过,引发运行时错误
• composer update 行为不可预测,甚至拒绝执行
冲突发生时,先别改文件,先看差异本质
打开冲突标记区域( 和 >>>>> branch-name),重点观察三类内容:
• packages 数组里是否新增/删除了同一包的不同版本(比如 "monolog/monolog": "2.10.0" vs "monolog/monolog": "3.0.0")
• packages-dev 是否有开发依赖增减(如 phpunit/phpunit 版本变动)
• content-hash 和 platform-check 值是否不同(这通常只是副产物,不用手动改)
手动解决的推荐步骤
• 运行 git checkout --ours composer.lock 或 git checkout --theirs composer.lock 临时保留某一方,但**不要提交**
• 在该状态下执行 composer update --lock(不带包名),让 Composer 重新生成符合当前 composer.json 的 lock 文件
• 如果项目有多个分支各自更新了不同依赖,更稳妥的做法是:先切回主干(如 main),运行 composer update 拉齐基础依赖;再切回当前分支,只运行 composer require xxx 或 composer update xxx 补上本分支需要的变更,最后 composer update --lock
• 确认无误后,用 git add composer.lock 提交——此时的 lock 文件才是语义一致、可复现的
CI 和团队协作中容易忽略的点
• GitHub/GitLab 的自动合并建议(如 “Resolve conflicts” 按钮)对 composer.lock **完全不可信**,它只会做文本合并,不校验依赖有效性
• 有些团队禁用 composer update,只允许 composer install,但这会让 lock 冲突变成“无法安全解决”的死结
• 如果两个分支都修改了同一个包(比如都升级了 guzzlehttp/guzzle),但版本号不同,不要手动改 JSON 字段——交给 composer update guzzlehttp/guzzle,它会处理所有传递依赖










