私有仓库必须置于repositories数组首位,否则会被后续源覆盖;因composer按数组顺序线性匹配,首个返回200且含目标包元数据的源即生效,后续全跳过。

私有仓库必须放在 repositories 数组最前面,否则会被镜像或 packagist.org 覆盖——这不是建议,是 Composer 的硬性匹配逻辑。
为什么私有包总被公共源覆盖?
Composer 查找包时,从 repositories 数组第一个元素开始发请求,只要某个源返回 HTTP 200 + 含目标包的 packages.json,就立刻锁定使用,后续所有源(包括你写的私有仓库)全部跳过。常见错误是把阿里云镜像写在前面、私有源放后面,结果 myorg/utils 直接从 packagist.org 拉了同名但不同内容的包。
- 私有仓库类型必须是
"type": "composer"(不是vcs),才能参与全局元数据匹配 -
vcs类型(如git@github.com:myorg/utils.git)只对显式composer require myorg/utils生效,不参与自动依赖解析 - 如果私有包 name 和 public 包完全一致(如
monolog/monolog),且私有源没放第一位,Composer 根本不会查它
正确的 repositories 数组顺序
顺序不是“推荐”,而是执行路径:从上到下线性扫描,短路退出。一个典型安全顺序如下:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
{
"repositories": [
{
"type": "composer",
"url": "https://pkg.myorg.com"
},
{
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
},
{
"packagist.org": false
}
]
}
- 私有源放首位:确保
myorg/*类包 100% 从内网拉取 - 镜像放第二位:覆盖大部分公共包,避免直连
packagist.org -
{"packagist.org": false}必须作为独立数组项,写在末尾——键名不能拼错,不能嵌套,不能少引号 - 删掉
vendor和composer.lock再运行composer install,否则 lock 文件里仍记着旧源的 hash
怎么验证顺序真生效了?
别信注释,也别靠感觉。执行以下命令看真实配置:
-
composer config repositories(项目级)或composer config -g repositories(全局),输出中应明确看到你的私有 URL 在第一行,且含"packagist.org": false - 加
-vvv运行composer update myorg/utils,日志里第一行 GET 请求必须是你的私有源地址,而不是https://repo.packagist.org - 如果出现
Could not fetch https://pkg.myorg.com/packages.json,说明顺序对了但网络/认证失败;如果出现Could not fetch https://repo.packagist.org/packages.json,说明packagist.org没禁用成功
容易被忽略的细节
私有仓库 URL 结尾必须带斜杠(https://pkg.myorg.com/),否则部分版本 Composer 会拼出错误路径;若用自签名证书,必须全局配置 ssl.cafile 并确认 PHP 进程有读取权限——这个配置不写进 repositories,但它失效会导致私有源直接 60 错误退出,根本走不到顺序判断这一步。










