composer install 从不主动更新 lock 文件,仅在校验失败时被动修正;真正修改 lock 的只有 composer update、require、remove;ci/cd 应用 --locked 确保一致性,--force-reinstall 可重装 vendor 而不改动 lock。

composer install 本来就不更新 lock 文件
这是 Composer 的设计前提:只要 composer.lock 存在且合法,composer install 就只读它、不改它。你不需要“防止”它更新 lock——它根本不会动。
常见误解是看到 lock 文件时间戳变了、内容有增删,就以为 install 更新了它。其实那是 Composer 在“修复不一致”,比如你删了 composer.json 里的某个包但没清理 lock,install 会主动剔除 lock 中已不存在的条目,这不是更新,而是校验失败后的自动修正。
- 真正触发 lock 修改的命令只有:
composer update、composer require、composer remove -
composer install --locked是最保险的用法:它明确要求 lock 必须存在且与 composer.json 兼容,否则直接报错退出,不自作主张 - CI/CD 中务必加
--locked,避免因漏提交 lock 导致 install 退化为 update 行为
为什么有时 install 后 lock 文件还是被改了
不是 install 主动改的,而是它发现 composer.lock 和 composer.json 不兼容,被迫做最小修正以维持可安装状态。典型场景包括:
-
composer.json里删了一个包,但 lock 文件里还留着它的记录 - 修改了 PHP 版本约束(如
"php": "^8.1"→"php": "^8.2"),而 lock 中 platform 声明仍是旧版本 - require-dev 区块有变动,但 lock 没同步,install 会清理掉 dev 区块中已不存在的包
这种“被动修正”不可控,也不可复现。要彻底避免,必须保证每次改 composer.json 后都运行 composer update --lock-only 同步 lock。
想强制重装但不碰 lock,用 --force-reinstall
composer install --force-reinstall 是唯一符合“不动 lock、只重装 vendor”的操作:它跳过文件存在性检查,强制按 lock 记录重新下载、解压、执行 post-install-cmd 脚本,连 autoload.php 都重建。
- 比
rm -rf vendor && composer install更快:不删目录结构,省去反复创建符号链接和目录的开销 - 保留 lock 完全不变,结果 100% 可复现
- Windows 下若报 Permission denied,先关掉所有 PHP 进程(Swoole/Xdebug)、IDE 索引服务,再试
- 如果某些间接依赖没被覆盖,加
--with-all-dependencies确保整棵树重装
容易被忽略的锁文件时效性问题
composer.lock 只保证“当时能跑”,不保证“永远可用”。比如:
- 某包的 2.9.0 版本被作者从 Packagist 下架,lock 里记着它,install 就会失败
- 私有仓库地址变更,但 lock 还存着旧 URL,install 会卡在下载环节
- PHP 升级后,lock 中某个包的
conflict规则触发,install 直接退出
这些情况和 lock 是否被修改无关,而是外部环境已变。此时 --force-reinstall 也救不了——你得先解决源不可达或平台不兼容的问题。











