必须手动删除私有源元数据缓存目录(如~/.composer/cache/repo/https---gitlab.example.com-...),因composer clear-cache不清理repo/下缓存,导致update始终读取过期packages.json而拉不到新代码。

私有VCS仓库更新后仍拉旧代码?元数据缓存没清对地方
Composer 读取私有 Git 仓库(如 GitHub/GitLab 私有项目)时,会把 packages.json 元数据缓存在 ~/.composer/cache/repo/https---your-gitlab.com/ 这类路径下。一旦这个目录存在,composer update 就跳过 HTTP 请求,直接用缓存里的旧版本列表——哪怕你刚 push 了新 tag 或改了 dev-main 分支,它也“看不见”。
必须手动删掉对应 repo 缓存子目录,否则所有后续操作都基于过期索引。
- 先确认你的私有源 URL:
composer config --list | grep repositories,找到类似repositories.0.url的值(如https://gitlab.example.com/api/v4/groups/my-group/-/packages/composer或更常见的https://gitlab.example.com/myorg/my-package.git) - 把 URL 转成缓存路径:把
https://换成https---,所有/换成-,末尾不加斜杠。例如https://gitlab.example.com/myorg/my-package.git→https---gitlab.example.com-myorg-my-package.git - 执行删除:
rm -rf $(composer config --global cache-dir)/repo/https---gitlab.example.com-myorg-my-package.git - Windows PowerShell 用户注意:
$(composer config --global cache-dir)需加.Trim(),或直接用$env:APPDATA\Composer\Cache\repo\https---gitlab.example.com-myorg-my-package.git
为什么 composer clear-cache 不管用?它根本不动 repo 缓存
composer clear-cache 只清 files/(ZIP 包)、vcs/(Git 克隆副本),但 repo/ 下的元数据缓存被明确排除在外——这是 Composer 的默认行为,不是 bug。
所以你跑完 clear-cache 再 update,日志里依然出现 Reading /path/to/cache/packages.json,说明它还在读旧索引。
- 验证是否真清掉了元数据缓存:运行
ls $(composer config --global cache-dir)/repo/,确认目标子目录已不存在 - 如果只是想临时验证,可改用
composer update --no-cache强制跳过全部缓存(包括repo/),但别在 CI 中长期用——太慢、耗流量、易触发镜像限流 - CI 场景推荐组合清理:
rm -rf $(composer config --global cache-dir)/repo/https---*+rm -f composer.lock vendor/composer/installed.json
拉取 ZIP 包还是旧的?dist 缓存 hash 复用导致内容错配
私有 VCS 仓库若配置了 "dist": {"type": "zip", "url": "..."}}(常见于 Satis 或 GitLab Package Registry),Composer 会把 ZIP 下载到 ~/.composer/cache/files/{vendor}/{package}/{hash}/。问题在于:这个 {hash} 是 dist URL 的 SHA256,不是 ZIP 内容的校验值。如果你覆盖上传了同 URL 的新 ZIP,本地缓存不会自动失效。
结果就是:元数据已更新、版本号也对,但解压出来的仍是旧文件。
- 查当前锁文件中该包的 dist hash:
grep -A5 '"myorg/my-package"' composer.lock | grep shasum - 定位并删除对应缓存:
rm -rf ~/.composer/cache/files/myorg/my-package/abc123456789(hash 来自上一步) - 或者更稳妥:删整个
files/子目录下的该包相关项:rm -rf ~/.composer/cache/files/myorg/my-package/* - 避免未来踩坑:私有源尽量用
type: vcs直接 clone,而非依赖 dist ZIP;若必须用 ZIP,请确保每次发布生成唯一 URL(比如带时间戳或 commit hash)
本地开发调试 path 仓库时,缓存残留比 VCS 更隐蔽
用 "type": "path" 引入本地包(如 "../my-package")时,Composer 除了缓存元数据,还会在 ~/.composer/cache/vcs/ 下保留一个 Git 快照(即使你没用 Git),同时在 vendor/ 下建 symlink。这两处缓存不清理,composer update 就不会重新读取你本地改过的 composer.json 或 PHP 类。
- 删干净三处:
rm -rf vendor/myorg/my-package+rm -rf ~/.composer/cache/vcs/*+rm -f vendor/composer/installed.json - 验证是否重载成功:加
-vvv运行composer update myorg/my-package,日志里必须出现Reading ./../my-package/composer.json,而不是Using version dev-main from cache - CI/Docker 环境中禁用
path:它只适合本地开发,部署时应切回真实私有 VCS 源,否则构建不可复现
最常被忽略的是元数据缓存路径的转换规则——少一个 - 或多一个 /,删的就是错目录;而 composer clear-cache 的“不清理 repo”行为,在文档里藏得很深,很多人直到 update --dry-run -v 看到仍在读旧 packages.json 才反应过来。











