composer安装失败后不能自动回滚,因其设计为单向状态机,不记录安装前快照,失败后vendor常处于半残缺状态而lock文件未变;必须通过git恢复旧lock、彻底删除vendor、再运行composer install来重建一致环境。

Composer 安装失败后不会自动回滚,vendor 目录大概率处于半残缺状态,lock 文件却没变——这不是“可恢复的事务”,而是必须手动重建的现场。
为什么 composer install 失败后不能自动清理残留
Composer 的设计是单向状态机:它只读 composer.lock,只写 vendor/,不记录任何安装前快照,也不保存操作日志。一旦中断(网络超时、磁盘满、权限拒绝),就可能出现:
Failed to download vendor/package: file_put_contents(): failed to open stream-
Could not delete vendor/autoload.php(被 PHP 进程锁住) -
Invalid zip archive(部分解压完成,但校验失败)
此时 vendor/ 里混着新旧文件,autoload.php 可能已重写但类文件缺失,composer.lock 却仍是原样——Composer 不会、也不能主动删掉它写了一半的东西。
用 Git 恢复 composer.lock 是回滚前提
Git 不是辅助工具,而是唯一可信锚点。没有干净的 composer.lock,就不存在“回滚”:
- 如果刚执行
composer install失败,且还没提交新 lock,运行git checkout -- composer.lock立即还原 - 如果 lock 已被覆盖并提交,用
git checkout abc1234 -- composer.lock(替换为含旧 lock 的 commit hash) - 务必确认换行符和末尾空行完整——Git 模式差异(CRLF/LF)会导致
content-hash校验失败 - 别跳过这步直接删
vendor/后跑composer install,否则 Composer 会按当前composer.json重新 resolve,装出来的不是原来那套依赖
彻底清空 vendor/ 才算真正“重来”
残留的 vendor/ 是多数“回滚看似成功实则失效”的根源:
- 必须用
rm -rf vendor(Linux/macOS)或rmdir /s vendor(Windows),不能只删子目录或留vendor/autoload.php - 特别注意
vendor/bin/下的脚本(如phpunit、phpcs):旧版本二进制可能仍在PATH中被优先调用 - 某些项目生成的
.phpstorm.meta.php或vendor/composer/autoload_*.php也会缓存旧映射,一并清除 - 顺手执行
composer clear-cache,避免本地缓存干扰 dist 包下载源
composer install 才是真正的“回滚命令”
它不解析 composer.json,只忠实地按 composer.lock 重建环境:
- 运行
composer install --no-dev --prefer-dist --optimize-autoloader(生产环境标准组合) - 若报
Root package requires a version of PHP that is not installed,说明 lock 文件中platform配置与当前 PHP 版本不匹配,临时加--ignore-platform-req=php或改composer.lock的platform.php字段 - 检查
post-install-cmd是否执行:旧 lock 对应的钩子(如生成配置、编译资源)可能未重放,必要时手动运行composer run-script post-install-cmd - PHP OPcache 未清会导致旧类仍被加载,需
opcache_reset()或重启 FPM/CLI 服务
真正容易被忽略的,是 composer.lock 的完整性校验(比如 Packagist 下架旧 dist 包导致 hash 不匹配)和 vendor/ 的物理级清空——这两点不到位,所有后续操作都只是在错误基础上打补丁。











