
Git钩子基础:藏在.git里的自动化小助手
可能你每天用Git提交代码,但从没注意过它藏着这么个宝藏功能。Git钩子其实就是一些脚本文件,当你执行git commit
、git push
这些命令时,Git会自动去特定目录找对应的脚本并执行。就像你每次出门前,家里的智能音箱会提醒你带钥匙、关煤气一样,Git钩子就是代码提交的“智能管家”,帮你在关键节点做好检查。
钩子文件在哪?长什么样?
你打开任何一个Git仓库,进到.git/hooks
目录里看看,会发现一堆.sample
的文件,比如pre-commit.sample
、pre-push.sample
。这些就是Git默认提供的钩子模板,不过它们现在只是“样品”,要让它们生效,得先把.sample
后缀去掉。比如把pre-commit.sample
改成pre-commit
,这个文件就变成可执行的钩子了。
这里有个小细节你要注意:这些钩子文件默认是Shell脚本(开头有#!/bin/sh
),但其实你也可以写成Python、Node.js甚至Ruby脚本,只要在文件开头指定解释器就行(比如Node.js脚本开头写#!/usr/bin/env node
)。我个人更推荐用Node.js写前端项目的钩子,毕竟前端开发者对JavaScript更熟悉,处理JSON、调用npm包也方便。
前端项目必须关注的3个核心钩子
不是所有钩子都常用,对前端开发来说,有3个钩子几乎是必备的,我把它们的作用和使用场景整理成了表格,你可以直接拿去参考:
钩子名称 | 触发时机 | 前端典型用途 | 是否阻塞操作 |
---|---|---|---|
pre-commit | 执行git commit时,提交信息输入前 | ESLint检查、Prettier格式化、CSS预处理器编译检查 | 是(脚本返回非0则阻止提交) |
commit-msg | 提交信息输入后,提交完成前 | 检查提交信息是否符合规范(如Angular提交规范) | 是(不符合规范则阻止提交) |
pre-push | 执行git push时,远程推送前 | 运行单元测试(Jest/Vitest)、构建打包检查 | 是(测试失败则阻止推送) |
为什么这3个钩子对前端这么重要?我举个自己的例子:去年带一个Vue项目时,团队里有个刚毕业的同学,写代码很快但总忘记格式化,提交后ESLint报一堆红。当时我们还没配钩子,每次代码合到develop分支,CI都会因为他的代码格式问题失败,整个团队都得等他改完重提。后来我给他的电脑配了pre-commit钩子,强制在提交前跑ESLint和Prettier,结果你猜怎么着?他提交的代码再也没出过格式问题,CI失败率直接降了一半多。这就是钩子的价值——把“靠人记”变成“自动化”,减少重复沟通成本。
前端钩子脚本实战:从单文件到团队共享
知道了钩子的基础,接下来就该动手写脚本了。别担心,前端钩子脚本没你想的那么复杂,甚至比写业务逻辑还简单。下面我就带你一步步实现最常用的几个钩子,再教你怎么让整个团队都用上这些配置,避免“我本地能用,你本地不行”的尴尬。
手把手写pre-commit钩子:自动格式化+代码检查
pre-commit钩子是前端用得最多的,主要解决“提交前代码不规范”的问题。假设你的项目用了ESLint和Prettier(现在前端项目基本都标配了吧?),那我们就写一个钩子,在提交前自动检查并修复代码格式,有严重错误就阻止提交。
在.git/hooks
目录下新建pre-commit
文件(记得删掉.sample),用Node.js写会更顺手,开头加上#!/usr/bin/env node
。然后思路很简单:先获取本次提交修改的文件(只检查变更的文件,避免全量检查太慢),再用ESLint检查这些文件,能自动修复的就修复,不能修复的报错并阻止提交。
我把核心代码贴出来,你可以直接抄作业(记得把路径换成你项目的实际路径):
#!/usr/bin/env node
const { execSync } = require('child_process');
const path = require('path');
try {
// 获取暂存区的文件列表(只包含.js,.jsx,.ts,.tsx,.vue文件)
const files = execSync('git diff cached name-only diff-filter=ACM | grep -E ".(js|jsx|ts|tsx|vue)$"', { encoding: 'utf-8' })
.split('n')
.filter(file => file.trim());
if (files.length === 0) {
console.log('没有需要检查的前端文件,提交继续~');
process.exit(0);
}
// 用Prettier自动格式化
console.log('正在用Prettier格式化代码...');
execSync(npx prettier write ${files.join(' ')}
, { stdio: 'inherit' });
// 把格式化后的文件重新加入暂存区(避免格式化后代码没提交)
execSync(git add ${files.join(' ')}
, { stdio: 'inherit' });
// 用ESLint检查
console.log('正在用ESLint检查代码...');
execSync(npx eslint ${files.join(' ')}
, { stdio: 'inherit' });
console.log('代码检查通过,可以提交啦!🎉');
process.exit(0);
} catch (error) {
console.error('❌ 代码检查失败,请修复错误后再提交');
process.exit(1); // 非0退出会阻止提交
}
这里有几个关键点你得注意:一是用git diff cached
获取暂存区文件,确保只检查要提交的代码;二是格式化后要git add
重新暂存,否则格式化的修改不会被提交;三是npx
确保用项目本地的ESLint/Prettier版本,避免全局版本不一致导致问题。我之前就踩过坑,全局装了Prettier 2.x,项目用的3.x,格式化规则不一样,钩子总是报错,后来换成npx就好了。
团队共享钩子:用husky告别“手动复制”
上面的脚本虽然好用,但有个问题:.git
目录默认不会提交到仓库,你本地配好了,团队其他人还得手动复制钩子文件,太麻烦了。这时候就需要一个工具帮我们管理钩子——husky(注意是h-u-s-k-y,不是哈士奇那个husky)。
husky是目前前端最流行的Git钩子工具,能帮你把钩子配置写到package.json
里,提交到仓库后,其他人安装依赖时自动启用钩子。它的下载量有多夸张?npm上显示每周下载量超过3000万次,几乎所有中大型前端项目都在用。
怎么用husky配置钩子?三步就能搞定:
先装包:npm install husky save-dev
,然后启用husky:npx husky install
。为了让其他人克隆项目后自动启用钩子,可以在package.json
里加个prepare脚本:"prepare": "husky install"
,这样npm install
后会自动运行husky install
。
比如创建pre-commit钩子:npx husky add .husky/pre-commit "npx lint-staged"
。这里的lint-staged
是个辅助工具,能只对暂存区文件运行命令(和我们刚才手动写的获取文件列表逻辑一样,但更成熟)。你需要先安装它:npm install lint-staged save-dev
,然后在package.json
里配置:
json
“lint-staged”: {
“*.{js,jsx,ts,tsx,vue}”: [“prettier write”, “eslint fix”]
}
这样pre-commit钩子就会自动对暂存区的前端文件先格式化再检查,和我们之前手动写的脚本效果一样,但更简洁。
把.husky目录、
package.json里的prepare脚本和lint-staged配置都提交到Git,其他人拉代码后
npm install,钩子就自动生效了。
我去年给一个React项目配husky时,团队里有个同事用的是Windows系统,一开始钩子总不执行,后来发现是他没装Git Bash,Node.js脚本在Windows的cmd里跑不起来。解决办法也简单:让他装个Git Bash,或者把钩子脚本改成Shell格式(不过还是推荐用Node.js,跨平台兼容性更好)。
90%的人会踩的钩子坑:从“不执行”到“执行慢”
钩子配置看着简单,但实际用起来总会遇到各种小问题。我整理了几个前端最常踩的坑和解决办法,你遇到时可以直接对照排查:
(手动配置时),或者用husky(它会自动处理权限)。
获取项目根目录(Node.js脚本),或者
cd “$(git rev-parse show-toplevel)”(Shell脚本)。
或
yarn dlx调用项目本地工具,比如
npx eslint而不是直接
eslint。
只检查暂存区文件,或者给耗时操作加缓存(比如ESLint的
cache选项)。 我之前就被“执行慢”坑过:有个项目pre-commit钩子会跑全量ESLint,项目大了之后每次提交要等40多秒,同事都抱怨“还不如手动检查快”。后来我改成只检查暂存区文件,加上ESLint缓存,执行时间直接降到3秒以内,大家才愿意用。所以配置钩子时,性能也很重要,别让自动化变成负担。
如果你按上面的步骤配好了钩子,记得在团队里推广一下——刚开始可能有人觉得“多了一步麻烦”,但用一周后就会发现,代码提交变顺畅了,CI失败少了,合并代码时再也不用纠结格式问题。如果你在配置过程中遇到其他问题,或者有更好的钩子脚本思路,欢迎在评论区告诉我,我们一起完善这个“前端提交小管家”!
你试过手动改.git/hooks里的文件吧?我之前带团队的时候就踩过这个坑——当时为了让大家提交代码前都跑ESLint,我写了个pre-commit脚本,自己电脑上配好没问题,结果第二天同事小王提交代码,格式还是乱七八糟。我问他钩子呢?他说“啥钩子?我没看到啊”——后来才发现,.git目录是Git自己管理的,根本不会提交到仓库里,我本地改的钩子文件,他拉代码的时候根本拿不到。最后没办法,只能一个个同事电脑去手动复制脚本,还得教他们怎么改权限,Windows同事用cmd跑脚本又报错,折腾了一下午才弄好。这种“本地专属配置”最麻烦的就是团队不一致,你这里检查通过了,他那里没钩子直接提交,结果就是CI流水线天天红,代码库像个“野生动物园”,格式风格五花八门。
换成husky就省心多了,它就像个“团队配置快递员”,能把钩子设置打包塞进Git仓库里。你用husky创建的钩子(比如.husky/pre-commit文件)、package.json里的配置,全都能提交到代码库,其他同事拉完代码,跑个npm install,husky就会自动把钩子“安装”到他们的.git/hooks里,权限、路径这些麻烦事它全帮你处理了,不用再手动改chmod命令。之前那个Windows同事,用手动钩子时总提示“权限被拒绝”,换成husky后,他拉代码装依赖,钩子直接就能跑,再也没找我问过“钩子怎么不生效”。而且husky还有现成的命令,比如想加个pre-push钩子,直接敲husky add .husky/pre-push “npm test”就行,不用自己去.git/hooks里新建文件,比手动改方便不止一点点。现在我们团队所有人提交代码,钩子都是一模一样的配置,再也没出现过“我这里能过,你那里不行”的尴尬情况。
Git钩子文件修改后不生效怎么办?
首先检查钩子文件是否去掉了 .sample
后缀(如 pre-commit.sample
需改为 pre-commit
),文件名错误会导致Git无法识别。其次确认文件是否有可执行权限,终端执行 chmod +x .git/hooks/pre-commit
可添加权限。最后检查脚本语法,比如Node.js脚本开头是否有 #!/usr/bin/env node
,Shell脚本是否有语法错误,执行 ./.git/hooks/pre-commit
手动运行脚本可查看具体报错。
用husky管理钩子和手动修改.git/hooks有什么区别?
手动修改 .git/hooks
的钩子文件仅保存在本地,无法提交到Git仓库,团队成员需手动复制配置,易出现“本地不一致”问题。而husky会将钩子配置(如 .husky
目录、package.json
中的脚本)提交到仓库,其他成员拉取代码后执行 npm install
即可自动启用钩子,实现团队配置统一。 husky提供了更简洁的钩子管理命令(如 husky add
),无需手动处理文件权限和路径问题。
钩子脚本执行失败时,如何查看具体错误原因?
钩子执行失败时,Git会在终端直接输出脚本的错误信息,仔细查看终端日志通常能定位问题(如ESLint报错、文件路径错误等)。若输出信息不明确,可在脚本中添加调试日志,比如在关键步骤用 console.log
(Node.js)或 echo
(Shell)打印变量值。 手动运行钩子脚本(如 ./.git/hooks/pre-commit
)可直接观察执行过程,比通过 git commit
触发更便于调试。
除了pre-commit和pre-push,还有哪些钩子适合前端项目?
前端项目常用的钩子还包括 commit-msg
(检查提交信息格式,如是否符合Angular规范的 feat: xxx
格式)、post-commit
(提交后执行操作,如自动生成CHANGELOG或通知团队)、pre-rebase
(变基前检查代码冲突或规范)。例如 commit-msg
钩子可配合 commitlint
工具,强制提交信息标准化,方便后续版本管理和自动化日志生成。