Composer 不会自动触发元数据只读备份;仅当启用 cache-read-only: true 且写入 {$cache-dir}/repo 失败时,才降级使用已有缓存元数据。

什么时候会触发 Composer 元数据只读备份?
Composer 不会在 install 或 update 时自动做“元数据只读备份”——它压根没有这个内置动作。所谓“只读备份”,实际是人为配置 cache-read-only: true 后,Composer 在写缓存失败时的被动 fallback 行为,而非主动备份策略。
真正起作用的时机只有两个:
- 执行
composer install或composer update时,尝试向{$cache-dir}/repo写入新仓库元数据(如packages.json解析结果) - 该目录因权限限制、挂载为只读或
cache-read-only: true已启用,导致写入失败
此时 Composer 不报错退出,而是跳过写入,继续用已有缓存中的旧元数据解析依赖——这被误称为“只读备份”,本质是降级使用缓存副本。
cache-read-only: true 的真实作用边界
这个配置不是开关“是否备份”,而是开关“是否允许覆盖元数据缓存”。设为 true 后:
- 所有命令(
install、update、require)都禁止向repo/子目录写入任何新文件 - 不会清理过期元数据(
cache-files-ttl对 repo 缓存无效) - 如果本地缓存里根本没有某包的元数据(比如首次离线运行),
install会直接失败,哪怕COMPOSER_DISABLE_NETWORK=1已设
换句话说:cache-read-only: true 只保“读”,不保“全量可用”。它适合已预填充缓存的 CI 构建节点,不适合冷启动离线环境。
想真正控制元数据备份时机?得靠外部脚本
Composer 自身不提供 hook 或事件来拦截元数据写入并触发备份。若需精确控制(例如:每次 update 后自动 tar.gz 当前 repo/ 目录),必须绕过 Composer 原生机制:
- 在
composer.json的scripts段定义post-update-cmd,调用 shell 脚本打包{$cache-dir}/repo - 用
inotifywait监控repo/目录变更(仅限 Linux 宿主机) - 在 Docker 构建阶段,用
RUN composer update && cp -r $COMPOSER_HOME/cache/repo /backup/固化快照
注意:repo/ 下的文件是二进制序列化格式(非 JSON),不可人工编辑;备份后恢复只需原路复制回 {$cache-dir}/repo 并确保权限匹配。
容易被忽略的兼容性陷阱
不同 Composer 版本对只读缓存的容忍度差异很大:
- v2.5.x:遇到写失败会静默跳过,继续安装(看似“成功”,但可能用错版本)
- v2.8+:部分场景下会警告
Warning: Failed to write repo cache, using stale data,但不中断流程 - v2.9.6:若
cache-read-only: true且缓存缺失关键元数据,直接报错Could not load package xxx,不再降级
所以,依赖“只读备份”行为的脚本,在升级 Composer 前必须验证 repo/ 缓存是否已完整预热——否则上线即崩。


















