根本原因是VCS缓存按Git URL哈希索引,而团队成员的SSH配置、URL写法(如git@github.com vs https://)、Git host别名等差异导致哈希不一致,缓存无法复用;需统一使用小写https格式URL、禁用insteadOf重写,并避免开发机与CI共享同一vcs/目录以防分支污染。

为什么团队共享VCS缓存后 composer update 还老拉远程?
根本原因是 Composer 的 VCS 缓存(~/.composer/cache/vcs/)是按 Git URL 哈希索引的,但同一仓库在不同成员机器上可能因 SSH 配置、URL 写法(git@github.com vs https://github.com)、或 Git host 别名不同,导致哈希不一致,缓存完全不复用。
常见现象包括:Cloning into '/tmp/xxx' 重复出现、Updating /path/to/cache/vcs/xxx 日志没变、CI 构建仍频繁走网络。
- 统一所有成员的
repositories中 URL 格式:全部用https://(避免 SSH 权限/别名干扰),且域名小写、无尾部.git(虽然 Git 支持,但 Composer 哈希对路径敏感) - 禁用 Git 的
insteadOf重写规则(检查git config --global url."https://".insteadOf git@是否存在) - 团队首次同步时,可手动复制一份干净的
vcs/目录到共享 NAS 或 CI 缓存目录,再通过COMPOSER_CACHE_DIR环境变量统一指向
共享 VCS 缓存会不会导致分支错乱或版本污染?
会,但只发生在「多人共用同一份缓存目录 + 同时操作同一仓库」的场景下。Composer 的 VCS 缓存本质是 Git clone 的裸仓库(--bare),它不保存工作区状态,但会保留所有远程分支引用(refs/remotes/origin/*)。如果 A 成员执行了 composer update 拉了 dev-feature,B 成员又删掉了该分支,下次 B 的 composer update 可能仍看到旧引用,导致装错 commit。
- 不要让开发机和 CI 共享同一
vcs/目录;CI 应使用独立缓存,且每次构建前运行git remote update --prune origin清理陈旧分支(可在scripts.pre-update-cmd中加钩子) - 团队约定:私有 VCS 包的分支名必须带命名空间,如
team-a/feat-login,避免dev-master这类泛化名称被不同人反复覆盖 - 若发现版本异常,直接删对应缓存子目录(路径形如
~/.composer/cache/vcs/https---github.com-vendor-pkg.git/),而非整个vcs/
CI 环境中如何安全复用 VCS 缓存?
CI 的缓存生命周期短、环境隔离强,不能简单挂载宿主机 ~/.composer/cache/vcs。必须配合 Git 元数据一致性校验,否则容易出现「本地 OK,CI 报 Class not found」这类问题。
- 在 CI 脚本中显式设置
COMPOSER_CACHE_DIR=/cache/composer,并确保该路径被持久化(如 GitHub Actions 的actions/cache,Key 包含composer-vcs-${{ hashFiles('**/composer.json') }}) - 禁用
path类型仓库:CI 必须用真实 VCS 源,否则path的 symlink 机制在容器里失效,且无法被缓存复用 - 关键一步:在
composer install前加校验命令git -C /cache/composer/vcs/https---github.com-vendor-pkg.git rev-parse --verify refs/remotes/origin/main,失败则清空该缓存子目录再重试
缓存共享后,怎么快速定位某个包是否真用了本地 VCS 缓存?
靠日志判断最准,但默认不输出详细路径。必须加 -vvv 并关注三类线索:
- 出现
Using cached version of https://github.com/vendor/pkg.git→ 表示命中缓存(注意不是 “Using version x.x.x from cache”——那是 dist 缓存) - 出现
Cloning https://github.com/vendor/pkg.git→ 完全没走缓存,检查 URL 是否一致、vcs/下对应目录是否存在 - 出现
Executing command (CWD): git remote set-url origin https://...→ 正在初始化缓存,说明之前没命中,但后续会存
VCS 缓存的复用边界很窄:URL 字符串必须逐字匹配,Git 配置不能干扰,且缓存目录权限要允许所有构建用户读写。稍有偏差,就退回原始网络拉取——这点比 dist 缓存难控得多。


















