composer why --tree 才能真正溯源到项目根,因默认 why 仅返回一级上游;查不到常见原因包括包未安装、属 --dev 依赖、被 provide 虚拟替代或 composer.lock 缺失。

composer why 不能直接告诉你“谁在 composer.json 里写了它”,默认只返回一级上游依赖,必须加 --tree 才能追溯到你自己的项目根。
为什么 composer why 经常查不到源头
它只在 composer.lock 存在且目标包已实际安装进 vendor/ 的前提下才工作。常见失效场景包括:
-
composer show vendor/package返回空 —— 包根本没装,why就无从谈起 - 包是用
composer require --dev装的,但当前环境启用了--no-dev(比如生产部署) - 包被其他包通过
"provide": {"psr/log-implementation": "*"}虚拟提供,本身不落地,why psr/log-implementation必然失败 - 项目还没跑过
composer install或composer update,composer.lock缺失或过期
composer why --tree 才是真正有用的溯源方式
默认的 composer why monolog/monolog 可能只输出 laravel/framework,让你误以为是自己手动引入的;而加了 --tree 后会显示完整路径:
my-project
└── laravel/framework ^10.0
└── monolog/monolog ^2.0
这说明:你没在 composer.json 里写 monolog/monolog,是 laravel/framework 拉进来的。关键点:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 末尾出现的
my-project才是你自己的项目名,代表源头 - 如果某行结尾带
[dev],说明该路径来自require-dev,上线时可能被跳过 - 若路径中断(比如停在
symfony/console就没了),大概率是它用provide声明替代了目标包,不再继续解析
composer why 和 composer show --who 的分工差异
why 回答“为什么装了这个包”,show --who 回答“谁声明了对它的依赖”——两者语义不同,不能互换:
-
composer why psr/log输出类似monolog/monolog → laravel/framework → my-project,强调安装动因 -
composer show --who psr/log列出所有require了psr/log的已安装包(如monolog/monolog、laravel/framework),结果干净、不递归 - 想排除开发依赖干扰,两个命令都支持
--no-dev;但show --who不受虚拟提供影响,更稳定
真正卡住的地方往往藏在 why --tree 输出最深的那一行
缩进越深,说明约束越隐蔽。比如你看到:
my-project
└── foo/bar dev-fix-branch
└── guzzlehttp/guzzle ^7.0
而你想升级 guzzlehttp/guzzle 到 ^8.0,问题就出在那个 dev-fix-branch —— 它半年前为临时调试加进去,至今还钉在 composer.json 里,锁死了整个链路。这种非标准分支、本地仓库或 minimum-stability 设置,why --tree 会如实暴露,但不会自动帮你判断是否安全删除。










