crontab 中不能直接执行 composer update,因其默认在用户家目录运行导致找不到 composer.json;须用 cd /path/to/project && composer update --no-interaction,并建议先 --dry-run 验证。

composer update 为什么不能直接塞进 crontab
因为 composer update 默认会读取当前工作目录下的 composer.json 和 composer.lock,而 crontab 执行时的 $PWD 通常是用户家目录,不是项目根目录——结果就是报错 Could not find composer.json 或静默更新错项目。
- 必须显式指定工作目录:
cd /path/to/project && composer update - 加上
--no-interaction,否则遇到需要确认的包(比如 major 版本升级提示)会卡住 - 建议加
--dry-run先跑一次看会更新哪些包,避免半夜自动升了个不兼容的symfony/console导致队列崩掉 - 别用
composer install替代——它只按composer.lock装,不会拉新版本
怎么只更新特定包,避免全量翻车
全量 composer update 是最危险的操作,尤其在生产依赖多、锁文件陈旧的项目里。真正可控的做法是精确到包名甚至版本约束。
- 更新单个包:
composer update monolog/monolog - 更新一组包(用通配):
composer update "phpunit/*"(注意引号,防止 shell 展开) - 锁定小版本,跳过 major 升级:
composer update --with-dependencies --minor-only laravel/framework - 想看某包能升到哪版?先跑
composer show -l monolog/monolog查可用版本列表
更新后如何验证没坏,又不用手动点半天
自动更新完不验证,等于给线上埋雷。但人工验证成本高,得靠脚本兜底。
- 更新后立刻跑
composer dump-autoload -o,确保 autoloader 没因类路径变更失效 - 执行最小闭环检查:
php -m | grep -q 'opcache' && php -r 'echo "OK\n";'(基础 PHP 可运行) - 如果有 PHPUnit,加一行
./vendor/bin/phpunit --exclude-group slow --stop-on-failure -q,只跑快的单元测试 - 关键:把验证命令和更新命令串成一行,用
&&连接,任一环节失败就中断,避免继续往下走
CI/CD 里做自动更新更靠谱,但要注意 lock 文件权限
比起服务器上跑 crontab,用 GitHub Actions 或 GitLab CI 触发更新更安全——环境干净、路径明确、失败可追溯。但有个坑:生成的 composer.lock 可能被不同平台写入不同换行符或 JSON 格式,导致 diff 飘红或本地 composer install 报错。
- CI 中更新后务必提交
composer.lock,不要只提交composer.json - 在
.gitattributes里加一行:composer.lock text eol=lf,强制统一换行符 - CI 脚本里加
composer validate --strict,检查 lock 文件是否和 json 匹配 - 如果项目用了
platform配置(比如"php": "8.1.0"),确保 CI 的 PHP 版本和它一致,否则update结果不可复现
自动更新真正的难点不在命令怎么写,而在判断“该不该升”和“升了之后谁来担责”。锁文件变更是敏感操作,哪怕只是 patch 版本,也可能触发下游某个隐藏的 bug。所以每次更新后的 diff 必须有人盯,不能只靠机器跑完就完事。


















