必须在项目根composer.json的repositories中显式配置"type": "vcs"及可git clone的url(如git@gitlab.example.com:org/pkg.git),否则报“could not find package”;type写错或漏写将被静默忽略,且install不拉新代码,需update触发。

repositories 里配 vcs 是让私有 Git 仓库被 Composer 当成“包源”识别的唯一可靠方式——不配,composer require 就会直接报 Could not find package;配错,它会静默跳过或卡在认证环节。
怎么写 repositories 配置才有效
必须是项目根目录 composer.json 中的顶层字段,不是子包自己的 composer.json,也不是全局配置。
-
"type": "vcs"是硬性要求,写成"git"、"github"或漏掉该字段,Composer 都会忽略整个条目 -
"url"必须是能被git clone的地址:支持git@(如git@gitlab.example.com:org/pkg.git)、https://(如https://gitlab.example.com/org/pkg.git),但不能是网页地址(如https://gitlab.example.com/org/pkg) - 别用
package类型硬编码版本——它绕过 Git 更新机制,后续无法update,维护成本极高
为什么 dev-main 能拉最新代码,但 install 不生效
composer install 只读 composer.lock 里锁定的 commit hash 或 zip URL,完全不碰远程 Git。哪怕你刚 git push 了新功能,install 也无动于衷。
- 真正触发拉取的是
composer update vendor/package(指定包)或composer update(全量) - 如果
lock文件里存的是"dev-main",update会执行git fetch并检出最新 commit;如果存的是"v1.2.3",它只会在远程出现新 tag 时才更新 -
dev-main不校验语义化版本,也不参与哈希锁定逻辑——CI 环境里没锁死,可能今天通过、明天因新 commit 引入 BC break 而失败
HTTPS 和 SSH 认证的实际差异
HTTPS 方式靠 auth.json 注入凭据,SSH 方式靠系统 git 命令链路,二者调试路径完全不同。
- HTTPS 私仓必须在项目根目录或
~/.composer/auth.json中配置,格式为:{"http-basic": {"gitlab.example.com": {"username": "token", "password": "abc123..."}}}多一层http-basic包裹或字段名拼错,就会 401 且无提示 - SSH 方式看似简单,但 Composer 底层调用的是系统
git,所以ssh -T git@gitlab.example.com能通 ≠ Composer 能通——常见坑包括:未启用ForwardAgent(CI 场景)、~/.ssh/config里 Host 别名没匹配到、私钥权限不是 600 - GitHub/GitLab 推荐用 OAuth token 配全局:
composer config -g github-oauth.github.com <token></token>,避免每次改 URL
私有包自身的 composer.json 容易被忽略的约束
即使 repositories 和认证都对了,如果私有仓库里的 composer.json 不合法,Composer 会静默跳过,而不是报错。
-
"name"字段必须符合vendor/name格式:小写字母、数字、中划线、下划线(但 Packagist 规则禁用下划线,建议统一不用),且不能和require中声明的包名不一致 -
"version"不是必须字段,但至少得有一个可解析的版本标识:分支要带dev-前缀(如"dev-main"),tag 要符合语义化格式(v1.2.3可,my-v1.2.3不可) - 想精确锁定某次提交,可用
"dev-main#abcd123"(Composer 2.2+),但注意:这个 hash 是 commit id,不是 tag 名
repositories → 克隆 → 解析 composer.json → 匹配 require 中的 name/version 这一套流程硬凑出来的。任何一环断开,它都不会提醒你缺哪块,只会说“找不到包”。











