Composer install 仍 clone Git 仓库是因为未启用 cache-vcs true,且浅克隆生效需满足三前提:Git 服务支持 ls-remote --symref 和 archive、composer.lock 中包的 source.reference 为 commit hash(非分支名)、本地 ~/.composer/cache/vcs/ 缓存存在且完好。

Composer install 为什么还在 clone Git 仓库?
因为 Composer 默认对 VCS 类型包(type: "vcs")不启用浅克隆,每次 composer install 都会执行完整 git clone,尤其当包历史庞大、含大量二进制或大文件时,耗时飙升甚至超时失败。
这不是镜像源没换对,而是 VCS 缓存开关没开——即使你已配好阿里云镜像,只要没显式启用 cache-vcs,Git 操作仍按默认行为走。
-
composer config -g cache-vcs true是必须手动开启的开关,新版 Composer 不默认启用 - 该设置生效后,Composer 会对每个 Git 仓库做
--depth=1+--single-branch克隆,并复用~/.composer/cache/vcs/下的裸仓库 - 若项目中某包被声明为
"type": "package"或通过repositories手动添加了vcs源,但未在composer.json中显式指定"dist": {...},Composer 仍会 fallback 到 clone
浅克隆生效的三个硬性前提
只设 cache-vcs true 不够,它依赖底层 Git 行为和元数据完整性。以下任一缺失都会导致浅克隆失效,退化为完整 clone:
- 目标 Git 仓库必须支持
git ls-remote --symref和git archive—— 某些私有 GitLab 实例或老旧 Gitee 镜像因权限或配置关闭这些接口,Composer 就无法获取 commit hash 或生成 dist 包 -
composer.lock中对应包的source字段必须包含reference(即 commit hash),不能是dev-main这类分支名;否则 Composer 无法跳过解析阶段,强制重新 clone - 本地
~/.composer/cache/vcs/目录下对应仓库的裸 clone 必须存在且未损坏;若曾手动清过缓存、或 CI 容器未挂载该路径,首次 install 仍会完整 clone
如何验证浅克隆是否真正起效
别只看总耗时,关键看日志里有没有 Cloning 或 Checking out —— 这些词出现,说明仍在走 Git 流程;而 Installing from dist 或 Using cached 才代表走了缓存路径。
- 加
-v参数运行:composer install -v,搜索输出中是否含Cloning into;若仍有,说明某个包没命中缓存 - 检查缓存目录结构:
ls -la ~/.composer/cache/vcs/,应看到类似github.com-xxx.git/的子目录,且内部有objects/和refs/ - 对比两次 install 日志:第一次有
Cloning xxx,第二次同一包变成Using cached xxx,才是浅克隆+缓存协同生效
CI 环境下浅克隆容易失效的盲区
CI 构建容器每次都是干净环境,~/.composer/cache/vcs/ 默认不持久化,导致每次构建都重 clone —— 即使你开了 cache-vcs true,也没地方缓。
- 必须显式设置
COMPOSER_CACHE_DIR=/tmp/composer-cache,并让 CI 平台缓存该路径(如 GitHub Actions 的actions/cache@v3缓存.composer/cache) - Docker 构建时,
COPY . /app放太早会导致整个vendor/层失效;正确顺序是先COPY composer.json composer.lock ./,再RUN composer install --no-dev --prefer-dist,最后COPY . . - Alpine 镜像需提前装
git(apk add git),否则 Composer 会静默 fallback 到 zip 下载,但若包没提供 dist,则直接失败,无任何提示
浅克隆不是“设个开关就完事”,它和缓存路径、Git 服务能力、lock 文件精度、CI 缓存策略四者强耦合;漏掉任意一环,表现都是“怎么还是在 clone”。


















