项目级 repositories 会彻底覆盖全局配置,只要 composer.json 里存在 repositories 字段(哪怕只是空数组 "repositories": []),Composer 就丢弃所有全局配置;验证方式为执行 composer config repositories 查看实际生效配置。

项目级 repositories 会彻底覆盖全局配置
只要 composer.json 里存在 repositories 字段(哪怕只是空数组 "repositories": []),Composer 就会丢弃所有全局配置(~/.composer/config.json 中的 repo.packagist 或其他仓库定义),不是合并,也不是追加,是整块替换。
验证方式很简单:composer config repositories 输出什么,就是实际生效的配置。如果输出里还包含 https://repo.packagist.org/ 或其他你没写进去的源,说明项目配置没生效,或者你误写了无效字段(比如把 repositories 写成 repos)。
常见踩坑点:
- 脚手架模板自带
"repositories": {"packagist.org": false},但没配替代源 → 直接报Could not find package - 手动编辑
composer.json时多加了逗号或少写了引号 → JSON 解析失败,Composer 回退到默认源 - CI 环境用不同用户执行命令(如
sudo -u www),但composer config -g写的是 root 的配置 → 项目里又没配,结果啥源都找不到
repositories 数组顺序 = 实际查找顺序,但不是“挨个试”
Composer 不是按数组索引逐个发起 HTTP 请求、等超时再试下一个;它对每个仓库并发请求元数据(如 /packages.json),只要某个源返回 HTTP 200 + 有效 JSON(哪怕 {"packages":{}}),就立刻认定该源“支持当前包”,并停止后续检查。
这意味着:
- 私有源必须放在
repositories数组最前面 —— 否则同名包可能被镜像或官方源抢先命中 - 镜像源应声明为
{"type": "composer", "url": "https://mirrors.aliyun.com/composer/"},不能混写https://packagist.org/和镜像 URL,否则前者会先触发网络请求,一断就卡死 -
{"packagist.org": false}是哨兵对象,不是开关:必须单独成项、放在私有源之后、数组末尾;写在前面会导致查完私有源就直接退出,不往下找
全局 config -g repo.packagist 的三个硬性条件
composer config -g repo.packagist 命令极易静默失效,根本原因不是网络问题,而是三要素缺一不可:
- 键名必须是
repo.packagist(不是repos.packagist、packagist.org或mirror) - 中间的
composer是type值,不能省略、不能为空、不能写成composer.org - URL 必须是 HTTPS 且末尾带
/(https://mirrors.aliyun.com/composer/✅,https://mirrors.aliyun.com/composer❌)
验证是否写入成功,只看这一行:composer config -g repo.packagist。输出必须是完整 JSON 对象,形如 {"type": "composer", "url": "https://mirrors.aliyun.com/composer/"}。空、null 或报 Key does not exist,说明压根没写进去。
临时换源优先级最高,但不改任何配置
不想动 composer.json 或全局 config,只想验证某个镜像是否可用?用 --repository-url 参数:
composer install --repository-url=https://mirrors.aliyun.com/composer/
它会跳过所有已配置的源,直接连指定地址,优先级高于项目级和全局配置。适合排查问题,也适合 CI 中单次构建指定源。
注意:--repository-url 只影响当次命令,不持久化;且它只覆盖源地址,不改变 repositories 数组结构(比如不会帮你跳过私有源)。
真正容易被忽略的是缓存和 lock 文件:即使配置全对,vendor/ 和 composer.lock 里记录的仍是旧源地址的 hash,必须删掉重装才能让新镜像生效。


















