Composer VCS 缓存失效主因是 URL 不稳定或认证失败,而非缓存开关问题;需确保 Git URL 规范、SSH 配置正确、源类型为 vcs,并合理设置 cache-vcs-dir 为 cache-dir 的子路径。

Composer 的 VCS(如 Git)依赖默认会缓存到 ~/.composer/cache/vcs/,但这个缓存行为不是靠开关控制的,而是由 Composer 自动管理——只要 URL 可复用、Git 仓库未变、commit hash 已存在,就会跳过重复 clone。你真正需要干预的,是让它「别瞎缓存」或「缓存到对的地方」。
为什么 composer install 还在反复 clone 私有 Git 仓库?
这不是缓存失效,而是根本没进缓存流程。常见原因:
- 每次
composer update都生成新 commit hash(比如 dev-main 被 rebase),导致缓存 key 不匹配 - URL 写成
https://gitlab.example.com/org/pkg.git/tree/main——/tree/main后缀让 Composer 认为这是不可缓存的 HTTP 下载路径,直接绕过 vcs 缓存 - 用了 SSH URL(
git@gitlab.example.com:org/pkg.git)但宿主机没配置~/.ssh/config或 agent,导致每次 fallback 到密码交互或失败,缓存被跳过 - 私有源 type 写成
"package"而非"vcs",这种类型压根不走 Git 缓存,只解压 dist
cache-dir 和 cache-vcs-dir 的区别与实操设置
cache-dir 是总缓存根目录;cache-vcs-dir 是它的子目录,专存 git clone 出来的裸仓库(.git)。两者可以分开配,但没必要——除非你把 vcs 缓存挂到 SSD,其他缓存放 HDD。
正确设置方式(全局):
composer config -g cache-dir "/mnt/fast-ssd/composer-cache"<br>composer config -g cache-vcs-dir "/mnt/fast-ssd/composer-cache/vcs"
注意:cache-vcs-dir 必须是 cache-dir 的子路径,否则 Composer 会忽略它。验证是否生效:
composer config --global cache-vcs-dir
输出应为完整绝对路径,且该路径下应存在类似 https---gitlab.example.com-org-pkg.git/ 的目录。
手动清理 VCS 缓存比 composer clear-cache 更精准
composer clear-cache 会清掉 files/、repo/、vcs/ 全部内容,但很多时候你只想删某个仓库的缓存(比如改了 GitLab token 后旧 clone 失效):
- 只清指定 Git 仓库缓存:
rm -rf ~/.composer/cache/vcs/https---gitlab.example.com-org-pkg.git - 批量清所有 GitLab 缓存:
find ~/.composer/cache/vcs -name "*gitlab.example.com*" -delete - 清完后立刻试装:
composer install -vvv | grep "Cloning into",如果不再出现该行,说明命中缓存
别在 composer install 进程运行时删缓存目录,否则可能触发 Corrupted cache file 报错,因为 Composer 正在读取 .git/objects 中的 pack 文件。
CI/CD 中 VCS 缓存失效的典型场景
GitHub Actions 或 GitLab CI 默认不保留 ~/.composer/cache/vcs/,每次 job 都是干净环境。光靠 actions/cache 缓存 ~/.composer/cache 不够——你还得确保:
- 缓存 key 包含 Git 仓库 URL 的哈希(不能只用
${{ runner.os }}) - 使用
composer install --no-interaction,避免因 SSH 提示中断流程 - 若用 Personal Access Token,确保
composer config -g gitlab-oauth.gitlab.example.com在缓存 restore 后执行,否则认证失败导致重新 clone
VCS 缓存最脆弱的一环从来不是配置,而是 URL 的稳定性和认证链的完整性——一个带 token 的 HTTPS URL 和一个配好 ssh-agent 的 SSH URL,在缓存效率上天差地别,但后者一旦 agent 没起来,就彻底退化成无缓存状态。











