composer status仅检测source模式安装的包(含.git目录),默认prefer-dist为true导致90%包走zip安装、无.git,故不被扫描;空输出仅表示“source包未修改”,不等于vendor干净。

composer status 不是用来“检查所有本地修改”的通用工具,它只对以 source 模式安装(即带 .git 目录)的包生效;默认 prefer-dist: true 下 90% 的包走 zip 安装,status 根本不扫描它们——空输出 ≠ vendor 干净,只是“没检查到 source 包的改动”。
为什么 composer status 经常没输出,但 vendor 明明被改了?
它只扫描含 .git 目录的包,也就是通过 --prefer-source 安装的包。dist 模式(zip 解压)下 vendor/xxx 里没有 .git,status 直接跳过。
- 验证方式:
composer show monolog/monolog,若输出中无source字段,说明该包当前是 dist 模式,status对它完全静音 - 私有包若漏配
"type": "package"或没声明"source",即使你本地有 Git 仓库,Composer 也不会识别 -
untracked状态表示该包不在composer.lock中却出现在vendor/里,常见于手动git clone或删了composer.json的 require 行但没清vendor
怎么让 composer status 真正检测到修改?
核心动作只有一个:把目标包切换成 source 模式。旧的 dist 包不会自动转换,必须重装。
- 重装单个包:
composer update --prefer-source monolog/monolog - 全局强制
source(推荐):composer config prefer-source true,该命令会写入项目composer.json的config块 - 临时生效(如 CI):
composer install --prefer-source或composer update --prefer-source - 注意:
source模式要求包本身提供source地址(如 Git URL),且系统PATH中必须有git命令,否则 fallback 到 dist
看到 modified 后,怎么快速定位改了啥?
composer status -v 只列文件路径,不显示 diff 内容。真要看改动,得进包目录用 Git 命令。
- 手动流程:
composer status -v→ 找到包名(如symfony/console)→cd vendor/symfony/console→git diff HEAD --stat查概览,或git diff看完整差异 - 一行脚本查所有 modified 包的简略状态(Linux/macOS):
composer status | grep "modified" | cut -d' ' -f1 | xargs -I{} sh -c 'echo "\n=== {} ==="; cd vendor/{} && git diff HEAD --stat 2>/dev/null' - 注意:
composer status输出格式不稳定(加-v后字段顺序可能变),适合人眼扫,不适合写自动化脚本做逻辑判断
composer status 显示 modified,但你确定没改代码?
常见原因不是手动改了源码,而是依赖包自身在安装后执行了生成操作:
- Symfony 缓存写入
var/cache/(虽然不在vendor/,但容易混淆) - Laravel 的
storage/framework写入(同理) - 某些包在
post-install-cmd中生成文件,而这些文件未被.gitignore覆盖,导致git status报untracked,composer status却误判为“被改” -
composer status默认退出码为 0,即使发现修改也不中断流程——它只是告知,不是校验失败。CI 环境靠它验一致性是不够的
最常被忽略的一点:它不检查 path 类型仓库引入的包,也不校验 vendor/autoload.php 或 vendor/composer/ 下的自动生成文件;哪怕你删了整个 vendor/ 后只留一个手写的 monolog/monolog 目录,只要没 .git,它就当看不见。











