golangci-lint 规则由 .golangci.yml 三层结构协同控制:启用哪些 linter、各 linter 参数配置、文件/问题忽略策略;配错易致漏报、误报或 CI 卡死。

直接说结论:golangci-lint 的规则不是靠“开/关”堆出来的,而是靠 .golangci.yml 里三层结构协同控制——哪些 linter 启用、每个 linter 怎么调参、哪些文件/问题要忽略。配错一层,就可能漏报、误报或 CI 卡死。
怎么启用和禁用 linter:别用 disable-all + enable 列表硬凑
很多人一上来就写 disable-all: true 再挨个 enable,结果发现 govet 和 staticcheck 冲突,或者 gofmt 不生效。真实情况是:
-
govet和staticcheck都检查 nil 指针,但后者更激进;同时启用时,staticcheck默认会覆盖govet的同类诊断,不是简单叠加 -
gofmt实际由goimports或gofumpt替代更实用,原生gofmtlinter 在 v1.54+ 已标记为 deprecated - 推荐做法:先用默认配置(不写
disable-all),再针对性disable个别 linter,比如:linters-settings: errcheck: check-type-assertions: true linters: disable: - lll - stylecheck
为什么 .golangci.yml 里设置 skip-dirs 仍会扫描 vendor?
因为 skip-dirs 只作用于 run 阶段的路径遍历,而 vendor 目录是否被加载,取决于 Go module 模式和 modules-download-mode。常见错误现象:
- 本地
golangci-lint run跳过了vendor,但 CI 报错说 “cannot find package in other modules” - CI 中
golangci-lint启动时尝试解析vendor/modules.txt,但 Go 版本 GO111MODULE=on,导致模块解析失败 - 解决方法不是加更多
skip-dirs,而是显式控制模块行为:run: modules-download-mode: "readonly" build-tags: ["integration"] go: "1.21"
并确保 CI 步骤中执行go env -w GO111MODULE=on
issues.exclude-rules 怎么写才真正生效?
正则写错、路径没对齐、层级放错位置,都会让 exclude 形同虚设。关键点:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
-
path字段匹配的是**相对项目根目录的文件路径**,不是 GOPATH 或运行时 pwd;例如想排除所有测试文件,得写path: ".*_test\.go$",而不是_test.go - exclude-rules 是按顺序匹配的,**第一条命中即终止**,所以宽泛规则(如
path: ".*")必须放在最后 - 想排除某个 linter 对特定文件的警告,不能只靠
path,得组合linter和text:issues: exclude-rules: - path: "cmd/.*" linter: "unused" text: "field.*unused" - 注意 YAML 缩进:它必须在
issues:下一级,缩进不对(比如多了一格空格)会导致整个 section 被忽略,且无报错提示
CI 中 only-new-issues 失效的典型原因
这个参数看似智能,实际依赖 GitHub API 返回的 diff,很容易掉坑里:
- PR 基础分支不是
main或develop(比如基于 feature 分支再起 PR),golangci-lint-action无法准确计算变更范围 - 没传
github-token,或 token 权限不足(至少需要contents: read),导致获取 diff 失败,自动退化为全量检查 - 启用了
cache-invalidation-interval但没配skip-cache: false,缓存未命中时重跑全量,新增问题被淹没在历史问题里 - 正确配置示例:
steps: - uses: golangci/golangci-lint-action@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} only-new-issues: true skip-cache: false
最常被忽略的是:golangci-lint 的规则生效与否,不取决于你写了多少行 YAML,而取决于它实际加载了哪个 go.mod、以什么 build-tags 运行、以及当前目录是否在 module 根下。哪怕配置全对,cd internal/pkg && golangci-lint run 也可能因找不到 go.mod 而静默跳过全部检查。

















