CI/CD中必须用composer install而非update,因update会修改composer.lock导致构建不可复现;install则严格按lock文件安装,确保环境一致性,并需加--no-dev、--no-interaction、--optimize-autoloader参数。

CI/CD 中必须用 composer install,禁用 composer update
CI/CD 流水线里运行 composer update 是高风险操作,它会主动修改 composer.lock 并拉取最新兼容版本,导致构建结果不可复现。生产环境部署必须和本地开发、测试环境使用完全一致的依赖版本,而只有 composer install 能保证这一点——它只按 composer.lock 安装,不读取 composer.json 的版本约束做决策。
composer install 在 CI 中的正确用法
默认行为已足够安全,但需显式控制几个关键参数:
- 始终加
--no-dev:CI 构建生产镜像或部署包时,不应安装require-dev里的包(如 PHPUnit、PHPStan),避免体积膨胀与潜在冲突 - 推荐加
--no-interaction和--optimize-autoloader:跳过交互提示,生成优化后的类映射,提升运行时性能 - 确保
composer.lock已提交到 Git:这是install可复现的前提;若缺失,install会退化为update行为并报错(除非加--ignore-platform-reqs,但这是掩盖问题)
composer install --no-dev --no-interaction --optimize-autoloader
什么时候该运行 composer update?
仅限开发者本地环境,且需满足两个条件:
- 明确要升级依赖(例如修复安全漏洞、引入新特性),并已通过人工审查变更内容
- 更新后立即提交新的
composer.lock文件——CI 后续所有构建都基于这个新锁文件
CI 流水线中出现 update 命令,基本意味着流程设计错误:要么是误把开发流程混入部署阶段,要么是试图用 CI 自动“保版本最新”,这违背了可复现性原则。
常见错误现象与排查点
以下迹象说明 CI 中误用了 update 或锁文件管理失控:
- 构建日志里出现
Writing lock file或Generating autoload files之后紧接着有大量Installing ...版本号变动 - 同一 Git 提交 SHA,在不同时间触发的两次 CI 构建,最终安装的
monolog/monolog版本不一致 -
composer.lock文件未被 Git 跟踪,或被 .gitignore 忽略 - CI 脚本里写死
composer update --with-dependencies用于“确保安全”,实则制造不可控依赖漂移
锁文件不是“可选附件”,它是 PHP 项目在 CI/CD 中实现确定性构建的契约。漏掉它,或者绕过它,等于放弃对依赖树的控制权。










