GitHub Actions中composer install找不到私有VCS包,根本原因是repositories未生效:必须确保其为数组、type为"vcs"、URL可git clone、首位声明且{"packagist.org": false}独立置末,同时删lock与vendor后重装。

GitHub Actions里composer install找不到私有VCS包?先确认repositories是否生效
根本不是网络或token问题,而是Composer压根没去查你的私有仓库——它只认composer.json里repositories数组中显式声明的条目。如果这个数组写成对象、漏了type、URL不可git clone,或者被{"packagist.org": true}兜底覆盖,就会静默跳过。
必须满足这几点:
-
repositories字段是数组,不能是对象; - 私有源条目放在数组首位(避免被后续
packagist.org条目拦截); - 同时用国内镜像时,必须加
{"packagist.org": false}禁用兜底; - GitLab/GitHub私有仓库用
type: "vcs",URL必须能直接git clone,例如https://oauth2:<token>@gitlab.example.com/myorg/pkg.git</token>; - 改完
composer.json后,删掉composer.lock和vendor/,再跑composer install,否则旧lock会锁死旧解析路径。
CI中缓存VCS包失败?关键在~/.composer/cache + PHP版本绑定
VCS包(比如dev-main分支)不像Packagist包有固定dist ZIP,它依赖Git克隆+检出+解压,缓存不命中就等于重走全流程。只缓存vendor/没用:下次composer install仍要重新clone;只缓存~/.composer/cache也不够:PHP minor版本一变(如8.2.10→8.2.12),缓存就失效但动作不报错,结果白缓存。
正确做法是:
本地项目发布到GitHub的完整工作流助手。自动执行:安全检查(.gitignore、排除敏感.env/凭据文件)、补齐开源文件(LICENSE、.gitignore)、git init/commit/branch、创建远程仓库、首次推送、可选打tag。支持git filter-repo历史敏感信息重写、force push、tag管理。Windows下走Credential Manager自动认证。触发词:"发布到GitHub"、"上传到github"、"
- 缓存路径设为
~/.composer/cache,这是Composer默认查找位置; - 缓存key必须含
${{ hashFiles('**/composer.lock') }}——VCS包的解析结果最终由lock文件锁定; - key里还得绑死
php-version(建议写'8.2'而非'8.2.x'),避免patch升级导致缓存不可复用; - CI步骤中必须用
shivammathur/setup-php@v2显式指定PHP版本和扩展(zip,git必装),不能靠系统自带PHP; - 运行
composer install时加--prefer-dist——对VCS源,Composer会尝试找dist ZIP;若没有,才fallback到--prefer-source,此时缓存~/.composer/cache完全无效。
Private Git token怎么塞进CI才安全又生效?别碰global config
在本地用composer config --global github-oauth.github.com <token></token>没问题,但在GitHub Actions里写这条命令等于把token明文打进日志。更糟的是,setup-php默认不读global config,它起的是干净容器。
安全且有效的做法只有两种:
- HTTPS方式:把token直接嵌进
composer.json的repositories.url里,格式为https://oauth2:<token>@github.com/user/repo.git</token>(注意oauth2:前缀); - SSH方式:用
actions/checkout@v4前加ssh-key步骤注入私钥,并把repositories.url改成git@github.com:user/repo.git; - 无论哪种,都得确保CI job的
permissions里开了contents: read(SSH需要)或没禁用secret输出(HTTPS需要); - 绝对不要在run步骤里执行
composer config写global配置——它不会被后续step继承,且容易泄露。
为什么缓存key总“not found”?检查hashFiles是否真能读到lock
actions/cache@v4提示Cache not found for input keys,大概率不是配置错,而是hashFiles('**/composer.lock')压根没读到文件。常见原因:
-
actions/checkout@v4后没加submodules: true,而你的composer.lock里引用了子模块包,导致lock文件实际没检出; - workflow用了
path-filtering,但composer.lock不在include列表里,checkout跳过了它; - 项目根目录下确实没有
composer.lock(比如你只提交了composer.json),那hashFiles返回空字符串,每次key都一样却永远不命中; - 缓存步骤放在
setup-php之前——某些旧版setup-php会在初始化时清空~/.composer,导致缓存恢复失败。
最稳的验证方式:在缓存步骤前加一行ls -la && cat composer.lock | head -n3,亲眼确认文件存在且可读。

















