Composer 不支持自动隔离私有/公共仓库,需通过 repositories 配置显式声明私有源(vcs 或 package 类型)并禁用 packagist;私有包 require 时须指定明确版本如 dev-main,且 CI 需配置鉴权。

Composer 本身不支持“自动隔离私有/公共仓库”的机制,所谓“隔离”必须靠 repositories 配置 + composer.json 中的依赖声明共同控制——核心在于:**私有包只能从私有源解析,公共包默认走 packagist.org,两者不会混用,除非你显式配置了错误的优先级或镜像规则。**
私有仓库必须显式声明为 vcs 或 package 类型
Composer 不会自动识别某个 Git URL 是私有的,它只认 repositories 里注册的源类型。如果你把私有 Git 地址直接写在 require 里(比如 "myorg/private-lib": "dev-main"),而没在 repositories 中注册对应源,Composer 就会报 Could not find package myorg/private-lib。
正确做法是:在根项目 composer.json 的 repositories 字段中,为每个私有仓库单独定义一条记录,并明确指定 "type": "vcs":
{
"repositories": [
{
"type": "vcs",
"url": "https://git.example.com/myorg/private-lib.git"
}
]
}
- 只声明
vcs类型,Composer 才会去该 Git 仓库解析composer.json并读取其name和version - 不要把多个私有仓库塞进同一个
vcs条目里——vcs类型不支持通配符或目录扫描 - 如果私有包没有公开的
composer.json(比如只提供 ZIP 发布),改用"type": "package",并手动补全name、version、dist等字段
packagist.org 默认启用,但可被 packagist 配置关闭
只要没显式禁用,Composer 总会把 packagist.org 当作最后兜底源。这意味着:即使你注册了私有 vcs 源,只要某包名(如 monolog/monolog)不在你的私有源里,Composer 仍会自动 fallback 到 Packagist。
若想彻底“隔离”,即禁止任何包走 Packagist(防止意外拉到公共版本覆盖私有 patch),需在 repositories 中加入空的 packagist 条目:
{
"repositories": [
{
"type": "composer",
"url": "https://packagist.org"
},
{
"type": "packagist",
"enabled": false
}
]
}
-
"type": "packagist"是特殊关键字,不是 URL;它控制的是全局 Packagist 开关 -
"enabled": false必须显式写出,否则该条目无效 - 关闭后,所有未在其他
repositories中明确定义的包都会报错——这是“隔离”的代价,也是验证配置是否生效的信号
私有包 require 时不能省略版本约束,且建议用 dev- 前缀锁定分支
私有 vcs 源不参与 Packagist 的索引缓存,Composer 每次都要实时探测 Git 分支和 tag。如果你写 "myorg/private-lib": "*",它可能匹配到任意 commit,行为不可控;更糟的是,某些 Git 服务商(如 GitLab)对未认证请求限流,导致 composer update 卡住或失败。
- 始终使用明确约束:
"myorg/private-lib": "dev-main"或"dev-feature/x",避免*或^这类模糊版本 - 私有包的
composer.json中version字段会被忽略,实际版本由 Git 分支/tag 名决定 - 若需固定某次提交,用
"dev-main#abc1234"格式(注意是#,不是@) - CI 环境中务必配置
COMPOSER_AUTH或auth.json,否则私有 Git 拉取会因鉴权失败静默跳过
真正难的不是加几行配置,而是让所有开发者和 CI 流程都一致地维护 repositories 列表、统一私有包的版本写法、并在团队内同步 auth.json 的生成方式——这些细节一旦错位,就会出现本地能装、CI 报错,或者 A 机器拉到私有版、B 机器拉到 Packagist 版的混乱局面。


















