composer 不自动合并 composer.json,需手动维护 scripts/config/extra 等原生字段;composer.lock 应用 git checkout --theirs + composer install --no-scripts + composer update --lock 重建;禁用已废弃的 merge-plugin,改用 repositories 或模板脚本管理共享配置。

Composer 合并配置时,composer.json 不会自动合并,必须手动处理
Composer 本身不提供配置文件合并功能。当你运行 composer require 或修改依赖后,它只会重写整个 composer.json(基于当前内存中的数据结构),不会“智能合并”你手写的字段。这意味着:如果你在 scripts、config、extra 里加了自定义内容,又没用 composer update --lock 保留 lock 文件一致性,很容易被覆盖或丢掉。
- 常见错误现象:
composer.json里的"scripts"消失了,或者"autoload"的"files"数组被清空 - 根本原因:很多工具(如某些 IDE 插件、CI 脚本)直接调用
Composer\Package\Loader\JsonLoader再 dump 回写,跳过了你本地的非标准字段 - 安全做法:所有手工添加的配置项,必须放在 Composer 原生支持的顶层键下(如
scripts、config、extra),且避免嵌套自定义结构;否则下次composer install可能静默忽略
冲突文件指的是 composer.lock,不是 composer.json
Git 合并时真正容易出冲突的是 composer.lock —— 它是二进制友好的 JSON,但结构扁平、字段多、顺序敏感。一旦多人同时增删包,Git 很可能标出大段冲突,而你不能靠“保留双方”来解决。
- 典型冲突块长这样:
{"packages": [<<<<<<< HEAD,"monolog/monolog": {"version": "2.9.0"},=======,"monolog/monolog": {"version": "3.0.0"},>>>>>>> feature/log-upgrade"} - 为什么不能手动修?因为
composer.lock还包含content-hash、packages-dev顺序、platform快照等隐式依赖,改错一个字段会导致composer install报Your lock file does not contain a compatible set of packages - 正确做法:放弃手动合并
composer.lock,统一用命令重建:git checkout --theirs composer.lock && composer install --no-scripts(先选一方 lock),再跑composer update --lock对齐依赖树
composer merge-plugin 是个陷阱,别用在现代项目里
这个插件曾被用来“合并多个 composer.json”,比如微服务共用基础配置。但它早已停止维护(最后更新 2019 年),不兼容 Composer 2.2+ 的加载机制,且会破坏 vendor/autoload.php 的生成逻辑。
- 常见错误现象:启用后
composer dump-autoload失败,报Class XXX not found,或autoload中的psr-4映射丢失 - 替代方案只有两个:用 Composer 的原生
repositories+package类型引入私有包;或把公共配置抽成独立的composer.json模板,用脚本(如jq)注入到主文件中 - 性能影响:merge-plugin 会让每次
composer install多扫描 3–5 个 JSON 文件,锁文件体积膨胀 20%+,CI 构建时间明显增加
真正需要合并的,其实是 autoload 和 scripts 的逻辑
很多人想“合并配置”,实际要解决的是:如何让团队成员在不同分支上各自加的命令或自动加载路径,最终能共存。这得靠结构设计,不是靠工具。
-
scripts合并建议:统一用script命令代理,比如定义"dev:build": "composer run-script --no-dev build:css && composer run-script --no-dev build:js",把具体实现拆到子 script,避免直接编辑顶层数组 -
autoload合并建议:不要在主composer.json里硬写"files",改用autoload-dev+require_once手动加载,或把共享代码做成独立包,用repositories引入 - 最容易被忽略的一点:Composer 会按
composer.json文件读取顺序解析autoload,但不会合并重复命名空间——后加载的会完全覆盖前一个,这点连很多资深 PHP 开发都没注意过










