composer.lock 必须与 vendor/ 严格一致,否则导致 ci 失败、环境不一致;误改主因是 ide 自动 update 或 require 忘加 --no-update;pre-commit 钩子可校验 lock 是否匹配 install --dry-run 结果。

只要项目用了 composer install 而不是 composer update,composer.lock 就必须和 vendor/ 严格一致——否则 CI 构建失败、本地环境不一致、依赖版本漂移全会找上门。
为什么 composer.lock 经常被误改?
常见原因不是故意,而是 IDE 自动执行了 composer update(比如 PhpStorm 的“auto-update dependencies”开关开着),或开发者顺手敲了 composer require 却忘了加 --no-update,又或者在 CI 流水线里混用了 update 和 install。
这类改动往往悄无声息:没有报错,git status 显示只有 composer.lock 变了,人一疏忽就 git add -A && git commit 了。
-
composer update会重写整个composer.lock,哪怕只改了一个包的小版本 -
composer require foo/bar默认触发更新,等价于composer update foo/bar - Git 不校验文件内容逻辑,只认“变了就提交”,它不管这变的是不是破坏性变更
用 pre-commit 钩子拦截非法修改
核心思路:在 git commit 前,检查当前暂存区里有没有 composer.lock,如果有,就验证它是否与 composer install --dry-run 产出的“应有状态”一致。
使用约定式提交(Conventional Commits)从 Git 历史记录中生成结构化变更日志,支持多种格式、AI 增强型描述以及可自定义的范围……
把下面这段脚本存为 .git/hooks/pre-commit(记得 chmod +x):
#!/bin/sh if git diff --cached --quiet -- composer.lock; then exit 0 fi <p>if ! composer install --dry-run --no-interaction >/dev/null 2>&1; then echo "❌ composer.lock 不匹配 vendor/ 或 composer.json —— 请先运行 composer install" exit 1 fi</p>
-
--dry-run不真的写文件,只做校验;失败说明lock和json或vendor/对不上 - 钩子只检查暂存区里的
composer.lock,避免干扰日常开发中还没git add的临时修改 - 如果项目没装 Composer,或
vendor/不存在,--dry-run也会失败,正好暴露环境问题
别漏掉 CI 和团队协作的配套动作
预提交钩子只是第一道防线,不能替代流程规范。
- CI 脚本里必须用
composer install --no-dev --prefer-dist,且禁止出现composer update - 所有
composer require操作都该加--no-update,后续统一跑composer update并提交lock(需明确 PR 描述) - 在
README.md里写清楚:“改依赖 → 先composer require --no-update→ 提交composer.json→ 后续由专人合并并更新lock” - 如果团队用 GitHub/GitLab,建议开启 branch protection,禁止直接 push 到 main,强制走 PR + CI 校验
最麻烦的不是钩子写不对,而是有人绕过钩子——比如用 git commit --no-verify。真要防死,得靠 CI 卡住,而不是靠本地钩子。但钩子至少能挡住 80% 的手滑和意识盲区。










