golangci-lint 在 lefthook pre-commit 中需限定检查暂存区 Go 文件、启用 --fast、用 exclude-rules 替代 skip-dirs、显式 git add 配合 --fix,并解决 command not found 和 exit code 4 问题。

golangci-lint 能通过 lefthook 在 pre-commit 阶段只检查暂存区变更文件,配合 --fast 和缓存机制,实测比全量扫描快 3–5 倍;但默认配置下它会忽略 .golangci.yml 中的 run.skip-dirs,且不自动 fix —— 这两点必须手动补救。
pre-commit 钩子里怎么调用 golangci-lint 才不卡住提交
lefthook 的 pre-commit 钩子默认运行所有匹配文件,但 golangci-lint 全量扫描整个项目会拖慢提交节奏。正确做法是让它只检查 git 暂存区里的 Go 文件:
- 在
lefthook.yml的pre-commit下添加files: git diff --cached --name-only --diff-filter=ACM | grep '\.go$',避免硬编码路径或 glob 泄漏未暂存文件 - 命令行必须加
--fast参数:golangci-lint run --fast --out-format=tab --issues-exit-code=1;不加会触发完整分析(如staticcheck的深度语义检查),单次耗时可能从 800ms 拉到 6s+ - 确保
golangci-lint版本 ≥ v1.57.2 —— 旧版本对--fast支持不完整,govet仍会全量跑
为什么 .golangci.yml 里 skip-dirs 不生效
lefthook 启动的子进程默认工作目录是项目根,但 golangci-lint 在 --fast 模式下会跳过配置文件中 run.skip-dirs 的路径过滤逻辑,只依赖命令行传入的文件列表。结果就是:即使你写了 skip-dirs: [vendor, testdata],只要 git diff 输出了 vendor/foo.go,它照样检查。
- 解决方法是改用
exclude-rules做内容级屏蔽:exclude-rules: [{path: "^vendor/", linters: ["all"]}, {path: "^testdata/", linters: ["all"]} ] - 注意正则要以
^开头,否则匹配失败;路径是相对于当前工作目录的相对路径,不是 git 输出的绝对路径 - 别依赖
skip-dirs做性能优化,它只在非--fast场景下起作用
如何让 pre-commit 自动修复格式问题而不中断流程
golangci-lint 的 --fix 参数能自动修正 gofmt、goimports 等支持修复的 linter,但 lefthook 默认不允许命令修改暂存区 —— 直接加 --fix 会导致「文件被修改但未重新 add」,提交失败。
- 在
lefthook.yml对应命令里加stages: [pre-commit]和always: true,并显式执行git add .: run: golangci-lint run --fix --fast && git add $(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')- ⚠️ 仅对可安全自动修复的 linter 有效(如格式类),
errcheck或staticcheck不支持--fix,强行加会静默忽略
常见错误现象和绕过方式
开发时遇到 golangci-lint: command not found 或 exit code 4 是最常卡住提交的两个点:
-
command not found:lefthook 默认不读取 shell 的$PATH,尤其在 macOS 上用 Homebrew 安装的二进制可能不在/usr/local/bin;解决方案是写绝对路径,比如/opt/homebrew/bin/golangci-lint,或在lefthook.yml顶层加env: {PATH: "/opt/homebrew/bin:$PATH"} -
exit code 4:这是 golangci-lint 的「有警告但无错误」退出码,默认被 lefthook 当成失败;若团队允许 warning 提交,需加fail-fast: false到该命令配置,并用output: quiet避免刷屏 - CI 和本地行为不一致?检查
lefthook install是否用了--force—— 没强制安装会导致钩子没真正写入.git/hooks/pre-commit
真正影响速度的从来不是工具本身,而是 --fast 模式下是否切断了不该走的分析链路,以及 exclude-rules 是否精准覆盖了生成代码和第三方目录。这些细节不调,再快的 Go 二进制也救不了每次提交多等 4 秒的体验。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











