composer why-not 是定位冲突源头的唯一可靠命令,报错出现“don’t install xxx”时须用完整版本号(如guzzlehttp/guzzle:8.0.0)执行,输出为反向依赖链,最后一行是根声明,往上逐行查看“(required by)”标识的互斥约束源。

composer why-not 是定位冲突源头的唯一可靠命令
报错里出现 don’t install xxx,别凭经验猜谁在拦路。必须用 composer why-not 带完整版本号查,比如 composer why-not guzzlehttp/guzzle:^8.0.0。输出是反向依赖链:最后一行是你 composer.json 里的声明,往上逐行看哪条 required by 提出了互斥约束——那就是真正卡住你的包。
常见陷阱:
- 写
guzzlehttp/guzzle:^8可能匹配不到元数据,必须写guzzlehttp/guzzle:^8.0.0或guzzlehttp/guzzle:8.0.0 - 输出为空?检查
require-dev——很多冲突来自phpunit/phpunit或mockery/mockery拖着老版sebastian/exporter,间接锁死symfony/console - 没加
--dry-run就直接执行require,可能把整个依赖树带偏;先试composer require laravel/framework:11.0.0 --dry-run看是否真能解出路径
composer show --tree 才是你项目的真实依赖快照
composer.json 是你写的愿望清单,composer show --tree 才是 vendor/ 和 composer.lock 里实际存在的结构。它会暴露你根本没意识到的间接路径,比如某包标着 (locked to 5.4.42) 或 (replaced)。
实操建议:
- 查某个包被谁引入:
composer show --tree | grep "symfony/console" - 过滤关键段:
composer show --tree monolog/monolog | grep -A5 -B5 "guzzlehttp/guzzle" - 看到
(provided)或(replaced),得去那个包自己的composer.json里确认它到底替代了什么、是否真能覆盖你当前需要的接口
定点更新必须带 --with-dependencies,否则等于没更新
全量 composer update 容易触发 SAT 求解器卡死,尤其依赖多的项目。升级单个包不加 --with-dependencies,Composer 默认拒绝更新其子依赖——哪怕新版本根本跑不起来。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
正确做法:
-
composer update monolog/monolog --with-dependencies—— 只动它和直系依赖 - 降级跨主版本(如从
guzzlehttp/guzzle:^8.0切回7.4.5),必须在composer.json里写死:"guzzlehttp/guzzle": "7.4.5",不能只写"^7.0" - 执行后立刻
git diff composer.lock,确认只有目标包及其直系依赖被改,没波及其他
镜像源和缓存不是解药,但配错会掩盖真实问题
中文镜像不能解决依赖冲突,只让冲突更快暴露出来。但如果你的 repositories 配置错误、或镜像源本身元数据滞后,会导致 why-not 查不到真实约束,误判为“无冲突”。
排查前必须确认:
- 镜像地址是否指向正确的 Composer 2 兼容源(如
https://packagist.phpcomposer.com已停用) - 执行过
composer clear-cache,排除本地缓存损坏干扰 - 用
composer diagnose检查网络连通性与 CA 证书有效性
最常被忽略的一点:冲突从来不是缓存或网络问题,而是 composer.json 里写的约束互相打架。删 vendor 或 composer.lock 只会让失败重演一遍——你得先看清谁在拦路,再决定改谁。










