pre-commit钩子需设可执行权限并以#!/bin/sh开头,golangci-lint修复后须git add -u暂存,.golangci.yml应跳过vendor等目录,团队须统一golangci-lint版本并校验。

pre-commit 钩子脚本必须可执行且带 shebang
Git 不会自动执行 .git/hooks/pre-commit,除非它被标记为可执行文件,并以合法的解释器声明开头。常见静默失败就是脚本没权限或缺 #!/bin/sh。
实操建议:
- 用
chmod +x .git/hooks/pre-commit赋予执行权限 - 脚本第一行必须是
#!/bin/sh(不要用#!/usr/bin/env bash,macOS 上可能不一致) - 避免在钩子里用
source或 Bash 特有语法,保持 POSIX 兼容 - 加一句
set -e让任意命令失败时立即退出,防止误通过
golangci-lint 检查后必须显式 git add -u
如果钩子调用了 golangci-lint run --fix 或其他自动修复类 linter(比如 goimports -w),修改后的文件默认不会进入暂存区。Git 仍认为工作区“脏”,而多数 pre-commit 流程会因检测到未暂存变更直接拒绝提交。
实操建议:
- 在
golangci-lint run --fix后紧跟git add -u,只暂存已跟踪文件的变更 - 别用
git add .,它会把新文件也加进去,可能误提交临时文件 - 加个判断:只有当
git status --porcelain有输出时才运行git add -u,避免无谓操作
配置 .golangci.yml 时注意 run.skip-dirs 和 linters-settings
默认配置下,golangci-lint 会扫描所有子目录,包括 vendor、testdata、examples,这不仅拖慢 pre-commit 响应,还可能触发误报(比如 vendor 里第三方代码的未使用变量)。
实操建议:
- 在
.golangci.yml的run区块明确设置skip-dirs:- vendor、- testdata、- examples - 对
govet这类敏感检查,可通过linters-settings.govet.checks关闭高误报项,例如- "atomic" -
staticcheck默认开启全部检查,但某些项目用旧版 Go SDK,需配linters-settings.staticcheck.go: "1.21"避免版本不兼容警告
团队协作中必须统一安装方式和版本
不同成员用 go install、brew 或二进制下载装的 golangci-lint,版本可能差小数点后两位,导致本地能过、CI 报错,或者 --fix 行为不一致(比如 gosimple 在 v1.56 改了函数内联提示逻辑)。
实操建议:
- 在
Makefile里定义install-lint:目标,强制用go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 - CI 脚本里也锁定同一版本,避免 “我本地好好的” 类问题
- 钩子脚本开头加校验:
if ! command -v golangci-lint > /dev/null || [[ $("golangci-lint --version") != *v1.57.2* ]]; then echo "Wrong golangci-lint version"; exit 1; fi
预提交钩子真正难的不是写脚本,而是让所有人每次 commit 都走同一套逻辑——权限、路径、版本、修复后暂存,四个点漏一个,守门就失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











