如何配置Lefthook使ESLint仅检查Git暂存区文件而非工作区内容?
如何配置Lefthook使ESLint仅检查Git暂存区文件而非工作区内容?
问题根源分析
你遇到的核心问题是:当前Lefthook配置里的 npx eslint {staged_files} 只是把暂存文件的路径传给ESLint,但ESLint默认读取的是本地工作区磁盘上的文件内容,而不是Git暂存区里的版本。所以哪怕你修复了工作区的错误但没重新暂存,ESLint会检查修复后的内容,而非你真正要提交的暂存区旧代码,导致Hook行为不符合预期。
下面给你两种可行的解决方案,推荐第一种更成熟的方案:
方案一:配合lint-staged使用(推荐)
lint-staged 是专门为pre-commit场景设计的工具,它会自动把Git暂存区的文件复制到临时目录,让检查工具(比如ESLint)只处理这些临时文件,完全隔离工作区的修改。
步骤1:安装依赖
在项目根目录执行:
npm install --save-dev lint-staged
步骤2:修改Lefthook配置
更新你的 lefthook.yml 里的pre-commit命令:
pre-commit: parallel: true commands: eslint: glob: "*.{js,ts}" run: npx lint-staged
步骤3:配置lint-staged规则
在项目根目录创建 .lintstagedrc.json 文件,指定对暂存区的ts/js文件执行ESLint:
{ "*.{js,ts}": ["npx eslint"] }
方案二:直接通过Git命令处理(无额外依赖)
如果你不想新增依赖,可以直接在Lefthook中通过Git命令提取暂存区内容,传给ESLint检查:
修改你的 lefthook.yml pre-commit部分的eslint命令:
pre-commit: parallel: true commands: eslint: glob: "*.{js,ts}" run: | exit_code=0 for file in {staged_files}; do # 读取暂存区文件内容,通过管道传给ESLint,同时指定文件名匹配规则 git show :"$file" | npx eslint --stdin --stdin-filename "$file" || exit_code=1 done exit $exit_code
原理:git show :<file> 会输出该文件在Git暂存区的原始内容,通过管道传给ESLint的--stdin参数;--stdin-filename 用来指定文件名,让ESLint应用你配置中对应文件类型的规则(比如你的TypeScript规则)。循环处理所有暂存文件,只要有一个检查失败就返回非0退出码,阻止提交。
验证解决方案
按照你的重现步骤测试:
- 把有错误的代码执行
git add . - 修复工作区的错误,但不执行
git add - 运行
git commit -m "Test"
现在Lefthook会正确检查暂存区的原始错误代码,ESLint会抛出原来的8个错误并阻止提交,完全符合你的预期。




