composer status 不用于查 git 子模块冲突,仅校验 composer.lock 与 vendor/ 一致性;子模块内嵌私有包与主项目约束冲突需通过 composer show --tree 和 git submodule status 对照排查。

Composer status 不是用来查 Git 子模块冲突的,它只报告 composer.lock 与 vendor/ 的一致性,对子模块完全无感。 真正要定位「Git 子模块 + Composer 依赖」混合场景下的冲突根源,得绕开 status,直接用 composer show --tree 和 git submodule status 对照看 —— 因为冲突往往发生在子模块里嵌了私有包、又和主项目 composer.json 的约束打架时。
为什么 composer status 永远不报子模块问题
composer status 只比对三样东西:当前 composer.json、composer.lock、已安装的 vendor/ 目录。它根本不会扫描 ./modules/xxx 或 ./packages/my-private-lib 这类 Git 子模块目录,更不会读取子模块内部的 composer.json。
- 即使子模块里写了
"monolog/monolog": "^3.0",而主项目锁死在^2.8,composer status仍会显示OK - 子模块更新了 commit 但没打 tag,主项目用
"my/private-lib": "dev-main",status也看不出版本漂移风险 - 子模块内含
conflict规则(如"php": "),而主项目要求 <code>php: "^8.3",status完全沉默
用 composer show --tree 揭露子模块引入的隐式依赖
子模块如果被主项目通过 repositories 注册为 vcs 类型,并被 require,它就真成了依赖图一员 —— 此时 composer show --tree 会把它列出来,且末尾带 (locked to abc1234)。
- 运行
composer show --tree | grep -A2 -B2 "my/private-lib",确认它是否出现在树中、锁定到哪个 commit - 若输出为空,说明子模块没被
composer.json显式 require,只是手动git submodule update拉下来的 —— 它的依赖不会参与 Composer 解析,但可能 runtime 冲突 - 重点看子模块自身依赖的包是否和主项目重复出现不同版本,例如
symfony/console在主项目树里是^5.4,在子模块树里是^6.2,这就是潜在冲突点
用 git submodule status + composer prohibits 定位真实拦路虎
当 composer update 报错说装不了某个包,而你知道子模块最近动过,就别猜,直接双线排查:
- 先跑
git submodule status,记录每个子模块当前 commit hash 和分支状态 - 再针对报错里提到的包(比如
laravel/framework:11.0.0)执行composer prohibits laravel/framework:11.0.0 - 如果输出里出现类似
my/private-lib v1.2.0 requires php: ^8.1 (for my/private-lib),那就坐实了:子模块的 PHP 版本约束卡死了主项目升级 - 注意:如果子模块没打 tag,
prohibits输出的版本号可能是dev-main,这时要结合git log -n 1看该 commit 是否真含不兼容变更
子模块内 composer.json 修改后必须重跑 install
子模块不是“静态资源”,它内部的 composer.json 改了,就等于新依赖规则上线 —— 但主项目不会自动感知。常见陷阱:
- 子模块加了
"require": {"ext-redis": "*"},主项目没装 redis 扩展,composer install不报错,php artisan运行时报 ClassNotFound - 子模块删掉了
"conflict": {"guzzlehttp/guzzle": ",但主项目 <code>composer.lock仍锁着guzzlehttp/guzzle: 6.5.8,实际运行时可能因 API 差异崩溃 - 正确做法:进子模块目录,
composer install --no-dev验证其自身依赖;再回主项目根目录,composer update my/private-lib --with-dependencies,强制重算并更新 lock 文件
子模块和 Composer 依赖的边界很薄,容易误以为“我拉了最新代码就万事大吉”,其实真正危险的是子模块内部约束和主项目 lock 文件的隐性脱节 —— 每次子模块有变更,都得同步检查 composer show --tree 输出和 git submodule status 输出是否一致,否则冲突大概率在部署后才爆发。











