composer拉私有gitlab包需在composer.json中声明repositories,type为vcs且url带.git后缀;认证须用~/.composer/auth.json(chmod 600)或git凭据重写;dev分支需设minimum-stability为dev。

私有包根本拉不下来?先确认 Composer 知道去哪找
Composer 默认只查 packagist.org,你 GitLab 上的 myorg/utils 它压根不会主动去扫。必须在项目级 composer.json 里显式声明源,否则报 Could not find package myorg/utils 是必然结果,不是网络或权限问题。
正确写法是加 repositories 数组,且类型必须为 vcs,URL 必须是完整、可 git clone 的地址:
"repositories": [
{
"type": "vcs",
"url": "https://gitlab.example.com/myorg/utils.git"
}
]
- 结尾的
.git不能省,https://gitlab.example.com/myorg/utils会失败 - 路径大小写敏感,GitLab namespace 是
MyOrg,URL 就得写成MyOrg/utils.git - 多个私有包就并列写多个对象,别嵌套、别用注释包裹
- 不要依赖全局配置——CI/CD 里没它,同事本地没配也会崩
认证失败:401 或 Permission denied 怎么办
GitLab 私有仓库必须鉴权,但 auth.json 放项目里无效,也别往 composer.json 里硬塞 token。真正可靠、可复现的方式只有两种:
- HTTPS + Git 凭据重写:用
git config --global url."https://oauth2:<token>@gitlab.example.com/".insteadOf "https://gitlab.example.com/"</token>,TOKEN 权限只需read_repository - SSH 方式:确保
git@gitlab.example.com:myorg/utils.git能在终端手动git clone成功;检查ssh-agent是否已加载密钥、~/.ssh/known_hosts是否已存主机指纹
注意:COMPOSER_AUTH 环境变量对 GitLab 不生效,因为它的 token 不支持 bearer header 自动注入;auth.json 必须放在 ~/.composer/auth.json,且 chmod 600,否则 Composer 直接忽略。
装不上 dev-main?稳定性策略没打开
私有包往往还没打正式 tag,直接 composer require myorg/utils 会跳过所有分支,因为 Composer 默认只认 stable 版本。你看到 dev-main 在 GitHub/GitLab 页面上明明存在,却提示“no matching package found”,就是这个原因。
- 临时解决:加明确版本约束,如
composer require myorg/utils:dev-main - 项目级统一策略:在
composer.json中设"minimum-stability": "dev"和"prefer-stable": true,这样没 stable 版时才退到 dev 分支 - 分支名必须严格匹配远程,新仓库默认是
main,写dev-master就会失败 - 自定义标签(如
v1.0.0-rc1)要符合语义化格式,推荐v1.0.0-rc.1,否则被忽略
CI/CD 里 clone 失败?部署密钥没跨仓库授权
GitLab CI 报 Permission denied (publickey) 或 Project not found or you don't have permission,大概率不是密钥没加载,而是部署密钥只绑了主项目,没在私有依赖仓库里启用。
- 每个私有包仓库(比如
myorg/utils)都得单独进 Settings → Deploy Keys,找到主项目用的那个公钥,勾选 “Allow write access”(只读够用)并点 Enable - 别指望“同 group 下自动互通”,GitLab 权限模型是 per-project 的
- SSH 配置写在
.gitlab-ci.yml里只是基础,没做这一步授权,一切白搭 - 如果用 HTTPS + TOKEN,CI 变量要设为
protected且只在对应分支运行,避免泄露
最常被跳过的环节是:以为配好主项目的 deploy key 就万事大吉,其实每个 repositories 里的 URL 都对应一个独立仓库,每个都得手动授权一次。











