golangci-lint --new-from-rev=master 无输出,根本原因是三个硬性前提未满足:配置文件名必须严格为.golangci.yml、必须与go.mod同目录、Git工作区必须干净;否则它会静默跳过扫描。

直接用 golangci-lint run --new-from-rev=master 就能只检查当前分支相对于 master 新增或修改的代码。但这不是“开箱即用”的功能,配置、路径、Git 状态三者不匹配,它就安静退出、不报错也不报问题。
为什么 golangci-lint run --new-from-rev 没输出?
这是最常踩的坑:命令看似执行了,但终端空空如也,CI 却一堆报错。根本原因不是工具失效,而是三个硬性前提没满足:
-
.golangci.yml文件必须存在且名字**严格为 .golangci.yml**(不是.golangci.yaml,也不是golangci.yml) - 该文件必须放在
go.mod所在目录(monorepo 中每个 module 各自一份,不能放在 Git 仓库根目录) - Git 工作区必须干净(
git status无 untracked/unstaged 文件),否则--new-from-rev会跳过所有文件
--new-from-rev 的实际行为和边界
它不是“diff 后再 lint”,而是让 golangci-lint 内部调用 git diff --name-only 获取变更文件列表,再对这些文件做包级扫描。这意味着:
- 只支持 Git,不支持其他 VCS;
--new-from-rev后面的 ref 必须是本地已有的分支/commit(如origin/main不行,得先git fetch) - 变更文件若跨多个 Go 包(比如同时改了
pkg/a/a.go和cmd/b/main.go),会按包分别扫描,但不会因跨包而漏掉依赖链上的问题 - 如果某次 commit 只改了注释或空格,
golines或gofumpt这类格式化 linter 可能不触发,但staticcheck仍会检查语义变更(比如把if x != nil改成if x == nil)
如何在 pre-commit hook 里安全启用增量检查
本地提交前自动跑增量 lint,是最实用的场景。但直接写 golangci-lint run --new-from-rev=HEAD~1 很容易崩——HEAD~1 在首次提交或 amend 时不存在。稳妥做法是:
立即学习“go语言免费学习笔记(深入)”;
- 用
git merge-base HEAD origin/main动态找共同祖先(比硬写master更健壮) - 加一层 fallback:当找不到 base 时,退化为全量扫描
golangci-lint run ./...(仅限本地,CI 不允许) - 排除生成代码目录:在
.golangci.yml里明确写skip-dirs: ["gen", "mocks", "pb"],否则 protobuf 生成文件一改,就扫出几百个 false positive
真正容易被忽略的是:增量扫描只管“文件是否变更”,不管“该文件是否被其他未变更文件引用”。比如你只改了 utils/log.go,但 http/handler.go 里调用了它一个刚删掉的函数——这个错误不会被 --new-from-rev 捕获,因为 handler.go 没变。这种跨文件语义断裂,必须靠全量扫描或 CI 阶段兜底。


















