pre-commit钩子中git add文件未纳入本次提交如何解决
问题原因
- 核心时序问题:Gradle默认开启守护进程模式,直接调用
gradlew时,可能将lint、spotlessApply任务提交给后台守护进程后立刻返回,导致后续git add执行时,spotlessApply还没完成文件修改。等pre-commit钩子执行结束、Git完成提交后,后台的Gradle任务才跑完文件修改,就会出现“提交先完成、改动后暂存”的假象。 - 暂存逻辑缺陷:
git add *是Shell在当前application目录下展开的通配符,只会暂存该目录下的非隐藏文件,无法覆盖仓库根目录的改动、隐藏文件改动、被删除的文件;老版本Git在子目录执行无路径参数的add命令时,也不会处理上层目录的改动,很容易漏暂存文件。
修复方案
调整后的pre-commit钩子脚本如下:
#!/bin/bash # 开启严格模式:任意命令执行失败、引用未定义变量、管道命令任意环节报错时立刻终止脚本,避免异常提交 set -euo pipefail cd application echo "Running Lint and Spotless" # 加--no-daemon参数强制Gradle前台同步执行任务,等所有任务跑完、文件修改完成后再往下执行 # 如果lint检测到不通过的问题,会返回非0退出码直接终止钩子,阻止提交 bash gradlew lint spotlessApply --no-daemon # 暂存全仓库所有类型的改动(新增、修改、删除,包含隐藏文件、所有目录下的改动) # :/ 代表强制以仓库根目录为操作基准,不受当前所在子目录影响 git add -A -- :/ exit 0
关键调整点
- 脚本开头加
set -euo pipefail,避免某一步执行失败后脚本继续运行,把错误代码提交上去。 - Gradle命令增加
--no-daemon参数,解决任务后台异步执行导致的时序错乱问题,确保文件修改完成后再执行暂存。 - 把有缺陷的
git add *替换为git add -A -- :/,不会漏暂存任何改动。如果只想暂存Gradle任务修改的application目录下的文件,可以把add命令改成git add -A -- application/,避免误暂存其他目录的无关改动。
调试阶段可以在
git add命令后加一行git status,执行提交时会直接打印暂存区文件列表,确认所有改动都被正确暂存后再删掉这行即可。如果觉得--no-daemon启动慢,Gradle7.0以上版本也可以替换为--no-build-cache配合守护进程使用,但优先推荐--no-daemon保证时序绝对正确。
内容的提问来源于stack exchange,提问作者Alessandro Violante
相关产品推荐
相关产品推荐

