composer show --tree是Composer≥2.2.0查看真实依赖树的唯一可靠命令,但需满足三前提:在项目根目录、vendor/存在、目标包已写入composer.lock;缩进表示层级依赖关系,不显示版本号,需配合composer show 包名查具体版本。

别用 composer show --tree 或 composer show -t 盲试——它们在不同 Composer 版本中行为不一致,且不加参数必然失败。真正能立刻跑通、反映真实安装状态的命令只有一个:composer show --tree(Composer ≥ 2.2.0),但必须满足三个前提:项目根目录、vendor/ 存在、目标包已出现在 composer.lock 中。
为什么 composer show --tree 报错或没输出
这不是命令写错了,是环境没到位。90% 的“查不到”问题都卡在这三步:
-
vendor/目录为空或根本不存在 —— 没执行过composer install或composer update,show --tree就无从读取实际安装快照 -
composer.lock文件缺失或为空 —— 它才是依赖解析结果的唯一权威来源,composer.json只是“愿望清单” - 包名输错:大小写敏感、
/不能省、vendor 名不能缩写(monolog/monolog≠monolog)
如果包只在 require-dev 里,又加了 --no-dev,它自然不会出现——这点常被忽略。
composer show --tree 输出里的缩进到底代表什么
缩进不是排版,是层级声明关系。每级缩进 = 一层直接 require 声明:
-
guzzlehttp/guzzle下缩进出现psr/http-client→ Guzzle 的composer.json明确写了它 - 同一包在不同缩进深度重复出现(比如一次在 2 级、一次在 5 级)→ 被多个上游包分别引入,版本不一致时极易冲突
- 括号里的
[dev-master]或[7.8.1]是实际安装版本,不是composer.json写的约束;看到v6.5.8但你写了"^7.0"?说明有其他包强制降级了它
注意:--tree 不显示版本号,只列包名;要查具体版本,得单独跑 composer show guzzlehttp/guzzle。
查“谁在用这个包”,别碰 composer depends
composer depends 是实验功能(2.4+ 默认关闭),遇到 provide、replace 或本地 path 仓库时大概率漏判。真正干净、确定、不绕弯的是:
-
composer show --who psr/log:扫描所有已安装包的require和require-dev字段,只返回“直接声明者” -
composer show --who --no-dev monolog/monolog:过滤掉开发依赖,专注生产链路 - 结果为空 ≠ 没人用 —— 可能是通过虚拟包(如
psr/log-implementation)间接提供,此时必须回看composer show --tree .全局结构
它只显示 A → B → C 中的 B,不会继续往上翻到 A;想看到 A,得对 B 再跑一次 composer show --who 或配合 composer why --tree。
想溯源到自己写的 require,--tree 必须加在 why 后面
composer why monolog/monolog 默认只返回一级来源(比如 laravel/framework),但你真正想知道的是:“我自己的 composer.json 哪一行写了它?”这时候不加 --tree 就等于白查。
- 正确姿势:
composer why --tree monolog/monolog,输出末尾出现your-project-name dev-main,才说明源头在你自己的require - 结尾带
[dev]?说明来自require-dev - 树在某一层中断(比如停在
laravel/framework就没了)?大概率是它用了provide声明虚拟包,没继续向下解析
纯文本树嵌套深了根本没法读,composer show --tree 本身不渲染图形,只是靠缩进定位路径。真要看清复杂拓扑,得用 composer global require baethon/composer-graph 配合 dot 命令生成可视化图——但前提是本地装了 Graphviz。











