必须同时备份composer.json和composer.lock,缺一不可;vendor/仅为构建产物,无版本锚点,无法还原精确依赖状态,且易受环境差异污染。

必须同时备份 composer.json 和 composer.lock,缺一不可。只备份 vendor/ 目录等于没备份——它不是源数据,而是构建产物,随时可能被污染或不一致。
为什么不能只 cp vendor/ 到 backup/
因为 vendor/ 里没有版本锚点:installed.json 可能被本地修改、autoload.php 依赖的 classmap 是生成结果、文件权限或符号链接在不同服务器上行为不一致。更关键的是,你无法靠它还原出“当时到底装了哪个 commit”——而 composer.lock 里明确记录了每个包的 dist.shasum 和 source.reference,这才是可重现的唯一依据。
-
composer.lock缺失 → 下次composer install可能拉到不兼容的次版本(如"monolog/monolog": "^2.0"装出 2.10.0 或 2.11.0) -
composer.json缺失 → 私有仓库配置(如repositories中的path或内网 Git 地址)丢失,还原后连元数据都解析不了 - 二者时间戳不匹配(比如
lock是 22:15 备份的,json是 22:10 的旧版)→ 还原时直接报Your lock file does not contain a compatible set of packages
备份命令必须带环境+时间戳,且集成进发布流程
人工执行 cp composer.{json,lock} backup/ 不可靠:没人记得加前缀,CI 日志里查不到上下文,回滚时根本分不清哪份对应哪次上线。
- 命名格式强制为:
releases/prod-20261104-2215-composer.json和releases/prod-20261104-2215-composer.lock(用$(date +%Y%m%d-%H%M)生成) - 禁止模糊名:
latest.lock、before-deploy.json、prod-backup—— 这些在故障复盘时毫无价值 - 必须写进
deploy.sh或 CI 脚本,在composer install成功后立即执行,而不是“等会儿再手动备份”
还原时常见报错及对应动作
从备份恢复后 composer install 报错,90% 是三者状态不一致:composer.lock、vendor/、installed.json 对不上。
- 报
Package is not installed或Class not found→ 先用jq . vendor/composer/installed.json验证 JSON 合法性,再检查包的install-path是否真存在对应目录 - 卡在
Resolving dependencies→ 运行composer install -v看停在哪一个包,再用composer show vendor/package确认该包是否还在当前镜像源中可访问 - 还原后
vendor/autoload.php不生效 → 不是文件丢了,是installed.json没注册或路径错,删掉整个vendor/,再跑composer install --no-cache
最易被忽略的一点:备份动作本身必须原子化。如果脚本在 cp composer.json 后、cp composer.lock 前崩溃,就会留下半份备份。所以实际脚本里应先 cp composer.json composer.lock releases/xxx-,再用 mv 批量重命名,确保二者严格同源同刻。


















