一名开发者在博客 packagemain.tech 上提出一种反向写法:.gitignore 里先写一个 *,默认忽略仓库里的所有文件。再用几条 ! 规则,把该追踪的文件类型逐一放行。
这不是 Git 官方推出的新功能,只是社区里流传的一种写法调整。但它把维护 .gitignore 的责任,从"记得排除什么"换成了"记得放行什么"。对文件类型稳定的小项目,这能省掉不少重复劳动;对生成物类型多变的复杂仓库,风险方向正好反过来——忘记放行,新文件会悄悄消失在版本控制之外。
一个"*"如何接管整个 .gitignore
传统 .gitignore 的逻辑是默认纳入,按项排除。新建文件默认会被 Git 追踪,除非手动写一行规则把它挡在外面。
反转方案把这个顺序倒过来,变成默认排除,按项纳入。
原文给出的例子是一个 Go 项目。先写 ,把仓库里的所有文件全部忽略。再用 !.gitignore、!.go、!go.mod、!go.sum 四条规则,把要追踪的文件类型逐一放行。IDE 配置、.DS_Store、AI Agent 留下的本地文档、环境变量文件,默认全部出局,不用一条条想起来去屏蔽。
这套写法有一个容易被忽略的技术细节。Git 忽略一个目录之后,通常不会再遍历这个目录内部。如果项目里有子目录,单靠 !.go 未必能把子目录里的 .go 文件放行回来,往往还需要加一条 !/,先把目录本身放行,Git 才会往里走。这条规则原文没有展开,实践时容易踩坑。
减少误提交,不等于更安全
这套写法解决的是"忘记排除",不是"忘记放行"。两种失误的性质不一样。
传统写法漏了排除规则,最危险的情形是新增的密钥文件、.env 没被排除。它会直接被追踪进仓库——这是密钥泄露最常见的路径之一。白名单写法漏了放行规则,后果方向相反。该追踪的代码文件被默认忽略,悄悄消失在版本控制之外。可能过很久才发现,代码根本没进仓库。
原文提到的 git check-ignore -v <文件名> 命令,就是为了排查这种反直觉的场景:文件明明在,却提交不上去,得靠命令行确认到底是哪条规则挡住了它。
白名单方案不会自动清理已经被 Git 记录的历史文件。已经提交的密钥、配置照样躺在提交历史里,想删干净得单独处理,靠加一条忽略规则解决不了。这套写法本身,也替代不了密钥扫描和代码审查。
对中小型项目的开发者和维护者:如果项目语言单一、文件类型基本稳定,可以在下一个新仓库里试试这套写法。落地前先把 git check-ignore -v 记在手边,每次引入新工具或新的生成目录,跑一遍确认有没有文件被漏挡在外面。
对负责仓库规范和敏感信息治理的工程团队:白名单写法不能单独依赖。CI 里仍然需要密钥扫描工具,代码审查也不能省。已经进入历史记录的敏感文件,要靠 git filter-repo 之类的工具单独清理,新增的忽略规则不会追溯生效。
谁该现在就试,谁该再等等
原文提到微软 typescript-go 仓库的 .gitignore 曾长达 207 行。这类数字会随仓库版本变化,只能当作"大型仓库规则会不断膨胀"的一个侧面例子,具体行数不必当真。
两种写法各有边界:
| 项目特征 | 更适合的写法 | 原因 |
|---|---|---|
| 单一语言、文件类型稳定的小项目 | 白名单(默认排除) | 维护成本低,误提交垃圾文件的概率小 |
| 多工具链、生成物类型多变的仓库 | 传统写法(默认纳入) | 白名单容易漏放行新类型,静默丢文件 |
| 涉及密钥或敏感配置的仓库 | 两种都不够,需搭配扫描工具 | 忽略规则不处理已提交的历史记录 |
对中小型项目,这更像一个可以试一试的技巧,不是要不要换的行业标准。真正需要谨慎的是工具链复杂、生成物类型多的仓库——换白名单之前,先想清楚每次新增文件类型,谁来负责同步更新那份白名单。
接下来值得盯的,是会不会有语言级的项目脚手架把这种白名单写法收进默认配置。如果没有,它大概率只会停留在小众技巧层面,不会成为普遍做法。
