私有源必须置顶且禁用packagist.org;Composer按repositories数组顺序逐个请求,首个返回HTTP 200且JSON可解析的源即被锁定使用,无fallback机制,type必须为"composer",URL末尾须带斜杠。

私有源必须置顶且禁用 packagist.org
Composer 不会 fallback,它只认 repositories 数组里第一个能返回有效 JSON 的源。如果你的私有源在数组第二位,而 packagist.org 在第一位(默认行为),那所有包——包括你私有仓库里的 acme/utils——都会从官方源拉,根本不会查你的私有源。
正确做法是:把私有源写在 repositories 数组最前面,并在**末尾**加一项 {"packagist.org": false}。注意三点:
-
packagist.org必须拼写精确,少一个点或大小写错误都不生效 - 这一项必须是独立对象,不能嵌套在其他配置里,也不能和别的源合并成一个对象
- 运行
composer config repositories后,输出里不应出现https://repo.packagist.org,而应明确看到"packagist.org": false
type 字段决定私有源是否参与全局匹配
只有 type: "composer" 的源(如 Satis、Private Packagist、Artifactory)才会被纳入元数据合并流程,从而影响 composer update 时的包发现逻辑。而 type: "vcs"(比如 Git 地址)只在你显式 composer require vendor/name 时才触发克隆,不抢优先级,也无法覆盖 laravel/framework 这类基础包。
常见踩坑点:
- 误把
type: "vcs"当作“高优先级私有源”放在数组顶部——它根本不会让composer update自动切过去 - 私有源 URL 末尾带
.git(type: "composer"下不允许),导致 404 或静默失败 - 私有源的
packages.json没声明你要的包名(如缺"acme/utils"条目),即使源在第一位,Composer 也会跳过它继续往下找
本地路径包要用 type: "path",且路径必须相对
想临时调试本地修改的包,别用 type: "vcs" 指向 ./my-package——它会被忽略。真正支持文件系统路径的是 type: "path",但规则极严:
-
url必须以./或../开头,绝对路径(如/home/user/pkg)或无协议路径(如my-package)全部静默失效 - 本地包的
composer.json中name字段必须和require里写的完全一致,包括大小写和 vendor 分隔符 - 若启用符号链接(
"symlink": true),需确认系统支持且权限正常;否则 Composer 会复制而非链接,改代码后得手动composer dump-autoload
验证到底走了哪个源?看 -vvv 日志,别信 composer.json 顺序
光改 composer.json 不等于生效。最可靠的方式是加详细日志跑一次:
composer update -vvv acme/utils
你会看到类似输出:
Reading composer.json of https://pkg.internal/acme/packages.json Found package "acme/utils" in version "2.3.1"
如果日志里先出现 Reading composer.json of https://repo.packagist.org/packages.json 并紧接着 Skipping package "acme/utils",说明你的私有源没被识别——要么 URL 错了,要么 packages.json 里没列这个包,要么 packagist.org 没禁用成功。
真正容易被忽略的是:私有源的 packages.json 必须包含完整 dist 和 source 字段,否则即使元数据能读到,下载 ZIP 时仍会回退到原始 GitHub 地址,而局域网内这一步必然失败。











