composer update 会重写 composer.lock 并按规则重算依赖树,而非同步远程状态;应优先用 install 还原环境,慎用 update 避免未测变更。

composer update 会改 lock 文件,但不等于同步远程依赖
执行 composer update 的本质是根据 composer.json 重新解析依赖图,然后拉取满足约束的最新可用版本(受 minimum-stability 和 prefer-stable 影响),并更新 composer.lock。它不是“把本地已安装包和远程仓库对齐”,而是“按规则重算一次依赖树”。如果你本地已有某些包,但 lock 文件里记录的是旧版本,update 后它们会被替换——哪怕远程没变,只要解析结果变了就会动。
常见误操作:在团队协作中直接运行 composer update 提交新的 lock,却没意识到这可能升级了某个间接依赖(比如 monolog/monolog 从 2.8.0 升到 2.9.0),而该变更未经过测试。
- 想“同步”远程状态,应先确认
composer.json是否准确描述了预期依赖 - 若只是想确保本地与
lock一致,用composer install(不带--no-lock) -
composer update --dry-run可预览实际会更新哪些包及其版本变化
composer install 不联网也能还原环境,但前提是 lock 文件可信
composer install 默认跳过依赖解析,只读 composer.lock 并按其中精确版本下载/软链接包。这意味着:即使 Packagist 宕机、网络不通,或某包已被作者删库,只要 lock 里记录的 dist URL 还能访问(或缓存存在),就能完成安装。
关键限制在于:lock 文件必须由可信来源提供。如果它是从别人分支复制来的,且对方曾手动编辑过 lock(比如改了 dist/sha256),install 可能校验失败并中断。
- CI 环境应始终用
composer install,禁用update - 本地开发若需复现线上环境,优先
git checkout对应 commit 的lock文件再install -
composer install --ignore-platform-reqs仅绕过 PHP 扩展等平台检查,不跳过lock校验
只更新单个包时,lock 文件仍会重写,但其他依赖版本不变
运行 composer update vendor/package-name 会强制重新解析该包及其子依赖,但会锁定其余所有包的版本(即保留 lock 中原有记录)。不过,lock 文件本身仍会被完全重写——时间戳、排序、甚至 JSON 格式都可能变化,导致 Git 脏 diff。
更隐蔽的问题是:如果该包的子依赖与项目中其他包存在版本冲突,composer 可能悄悄降级或升级无关包来满足约束,这种“涟漪效应”不易察觉。
- 更新前建议先
composer depends vendor/package-name查看谁依赖它 - 更新后务必检查
git diff composer.lock,确认没有意外变更 - 避免在
dev-master或dev-main等不稳定分支上执行单包 update
远程包删库或改名后,composer install 仍可能成功
Composer 缓存机制会让 install 优先从本地 ~/.composer/cache 拉取 zip 包,而非实时请求 Packagist。因此,即使原包已从 Packagist 移除、GitHub 仓库被删,只要缓存还在,install 就不会报错。
但这会造成“环境不可重现”风险:新机器无缓存时安装失败;或者缓存中包被恶意篡改(虽极小概率,但非零)。
- 生产部署前可加
composer clear-cache+install验证纯净环境 - 敏感项目建议用
composer config --global repo.packagist.org {\"type\":\"composer\",\"url\":\"https://packagist.org\"}显式指定源,避免镜像延迟或污染 - 长期维护项目应定期运行
composer outdated,及时发现已归档/废弃的依赖
lock 文件不是快照,而是依赖求解器的一次输出结果;它的权威性完全取决于生成时的上下文是否可控。任何绕过它的操作(比如手动改 vendor 目录、用 require --no-update 后不 update)都会让环境进入“无法描述也无法复现”的状态。










