composer如何检测未提交的composer.lock变更?(Git hooks集成方案)

7次阅读

在 pre-commit 钩子中应使用 git status –porcelain | grep ‘^[m?] composer.lock$’ 判断 composer.lock 是否被修改但未暂存,因其能准确捕获未暂存修改或未跟踪的新 lock 文件,而 git diff –quiet 会漏检;需先切至仓库根目录、显式指定 composer 可执行文件并检查 composer.json 存在性;同时注意权限、换行符、多模块等常见陷阱。

composer如何检测未提交的composer.lock变更?(Git hooks集成方案)

git pre-commit 钩子里怎么判断 composer.lock 被改了但没 git add

直接看工作区和暂存区差异就行,git status --porcelain 是最稳的判断依据。它输出格式固定,M 开头表示已修改未暂存,?? 表示未跟踪——这两种情况都该拦住。

  • git status --porcelain | grep '^[M?] composer.lock$' 能捕获未暂存修改或未跟踪的新 lock 文件
  • 别用 git diff --quiet composer.lock,它只对比暂存区和 HEAD,漏掉“改了但没 git add”的场景
  • 如果项目用 composer install --no-interaction 自动更新 lock,钩子得在 install 后立刻检查,否则 CI 会因 lock 不一致失败

为什么不能只靠 composer install 的退出码判断 lock 是否同步

composer install 默认不生成或更新 composer.lock,只校验现有 lock 是否匹配 composer.json。即使 lock 已过期(比如 composer.json 增加了依赖但 lock 没更新),它也静默成功,退出码仍是 0。

  • 真正能暴露不一致的是 composer update --dry-run:如果有差异,它会输出要变更的包,并返回非 0 码
  • --dry-run 很慢,尤其在 CI 上;预提交钩子里更推荐用 git status 快速拦截
  • 例外:当团队约定“所有变更必须先 composer update 再改 composer.json”,这时才适合在钩子里跑 composer update --dry-run

pre-commit 钩子脚本里怎么安全调用 Composer

钩子执行路径不一定在项目根目录,composer 命令可能找不到 composer.json,也可能误用全局 Composer 版本。

  • cd $(git rev-parse --show-toplevel) 切到仓库根,再执行后续命令
  • 显式指定 Composer 可执行文件:php ./composer.phar install --no-interaction(如果项目自带 phar)或 ./vendor/bin/composer install
  • 避免用 which composer,CI 环境或 docker 容器里常没有全局安装的 Composer
  • 加个 test -f composer.json 防御性检查,不是所有子目录都需要跑这个钩子

Git hooks + Composer 的典型失败场景

最常见的不是脚本写错,而是权限和路径错位。比如 macos 上钩子文件没 x 权限,或 windows 用户用了 CRLF 换行导致 #!/usr/bin/env bash 解析失败。

  • chmod +x .git/hooks/pre-commit 确保可执行
  • 钩子里别写 composer update 自动修复——这会让提交行为不可预测,且可能引入意料外的依赖升级
  • 如果项目同时用 pnpmyarn 管理前端依赖,注意它们生成的 pnpm-lock.yamlyarn.lock 也要一并检查,逻辑不能只盯 composer.lock

真正麻烦的是多层嵌套子模块(git submodule)里的 Composer 项目——钩子默认不递归触发,得手动遍历 .gitmodules,这点很容易被忽略。

text=ZqhQzanResources