.gitignore 测试器
.gitignore 是一份有顺序的规则表,对同一条路径,最后一条匹配的规则获胜。所以「这个文件为什么被忽略」的答案,往往不在你正盯着看的那一行。本工具接收该文件和一组路径,用 `git check-ignore -v` 的方式作答:逐条给出是否被忽略、做出决定的行号、以及那条规则的原文;如果决定来自上级目录而不是文件本身,还会把该目录一并标出。 最后这一点正是大多数 .gitignore 缺陷的藏身之处。git 从不进入被排除的目录,所以一旦 `build/` 被忽略,`!build/keep.txt` 就是一行死代码:文件是通过父目录判定的,那条取反规则根本没有被读到。本工具会专门把这种情况标出来,而不是让你自己猜;它还会列出没有匹配到任何粘贴路径的规则,多年前改过名的 coverage/ 或祖传的 Thumbs.db 往往就是这样浮出水面的。 匹配遵循 git 自己的解释,而不是 shell 通配:不含斜杠的规则在任意深度与文件名比较;含斜杠的规则锚定在 .gitignore 所在目录;结尾的斜杠把它限制为只匹配目录;`*` 不跨越斜杠,而独占一整段路径的 `**` 可以跨越;[0-9]、[!a-z] 这类字符类可用;行尾空格会被丢弃,除非用反斜杠转义;开头的 # 和 ! 可以转义;UTF-8 BOM 与 CRLF 换行会在解析前去掉。由于粘贴的路径不带类型信息,请给目录加上结尾斜杠:`build/` 按目录判定,`build` 按文件判定,仅这一点就会让所有「仅目录」规则的结论反转。 有两件事它无法告诉你。它只读一份 .gitignore,因此子目录里的 .gitignore、.git/info/exclude 以及 core.excludesFile 指定的全局文件都不在考虑之内,而它们都可能推翻这里的结果;它按大小写敏感比较,与 Linux 上的 git 一致,所以在 macOS 或 Windows 上开启了 core.ignorecase 的仓库可能忽略得更多。所有计算都在浏览器内完成,文件与路径都不会上传。
被忽略
5
未被忽略
3
规则数
7
死规则
1
git 不会进入被排除的目录,因此它下面的 ! 规则永远不会被读取。改为排除内容(dir/*)而不是目录(dir/),取反才会生效。
- .vscode/settings.json — !.vscode/settings.json (行号 10) · 来自被排除的父目录 .vscode/
| 路径 | 结论 | 行号 | 决定性规则 |
|---|---|---|---|
| src/index.ts | 未被忽略 | — | 没有规则匹配 |
| node_modules/react/index.js | 被忽略 | 2 | node_modules/来自被排除的父目录 node_modules/ |
| dist/ | 被忽略 | 3 | dist/ |
| dist/app.js | 被忽略 | 3 | dist/来自被排除的父目录 dist/ |
| debug.log | 未被忽略 | 6 | !debug.log |
| logs/debug.log | 未被忽略 | 6 | !debug.log |
| server.log | 被忽略 | 5 | *.log |
| .vscode/settings.json | 被忽略 | 9 | .vscode/来自被排除的父目录 .vscode/这条 ! 规则无法生效 |
上面的路径都没有匹配这些行。如果路径清单有代表性,它们就是可以删除的候选。
- 行号 4 coverage/
按大小写敏感的文件系统、仓库根目录下的单个 .gitignore 进行判定。
使用方法
- 把 .gitignore 原样粘贴到第一个框里。注释、空行、CRLF 换行和 BOM 都会按 git 的方式处理。
- 在第二个框里逐行写出要测试的路径,相对于仓库根目录。目录请在行尾加斜杠,`logs/` 这类仅目录规则的判定完全取决于它。
- 看表格。每一行给出是否被忽略、做出决定的行号和规则原文,也就是 `git check-ignore -v` 打印的三项信息,再加上被排除的父目录。
- 留意琥珀色提示框。当一条 `!` 规则确实匹配了路径,却因为父目录已被排除而无法生效时,它就会出现;这正是取反规则看起来没错却毫无作用的常见原因。
- 查看底部的死规则清单:没有匹配到任何粘贴路径的行。若路径清单具有代表性,它们就是可以删掉的候选。
常见问题
- 为什么写了 ! 规则,文件还是回不来?
- 因为 git 根本没有看到那个文件。遍历目录树时一旦发现某个目录被排除,git 就在那里停下,不再往里走,于是关于该目录内部的任何规则都不会被求值。官方文档说得很直接:如果一个文件的父目录被排除,就无法把它重新包含进来。写了 `logs/` 再写 `!logs/important.log`,日志依旧被忽略,本工具会显示决定来自那条目录规则。正确做法是排除内容而不是目录:先写 `logs/*` 再写 `!logs/important.log` 就可以,因为 `logs/*` 只匹配 logs 里的条目,并不排除 logs 本身。若要恢复整棵子树,标准写法是 `/logs/**`、`!/logs/keep/`、`!/logs/keep/**` 三行。
- build 和 /build 有什么区别?
- 规则里一个斜杠都没有时,它会在任意深度与路径的最后一段名字比较,所以 `build` 会同样忽略 /build、/src/build 和 /a/b/c/build。只要规则里出现了不是最后一个字符的斜杠,它就被锚定在 .gitignore 所在的目录,`/build` 和 `docs/output` 只从那个根往下匹配。这也解释了为什么在根目录 .gitignore 里只写 `node_modules`,连嵌套包里的 node_modules 也一并隐藏了:多数时候这正是大家想要的,但很少是有意写成这样的。想说「只在这里」,就在开头加一个斜杠。
- `logs/` 会匹配名为 logs 的文件吗?
- 不会。结尾的斜杠表示这条规则只匹配目录,因此名为 logs 的普通文件安然无恙,而任意深度的 logs 目录会连同里面的一切被忽略。这一点在本工具里尤其重要,因为粘贴的路径清单不携带类型信息:git 是查看真实文件系统来判断的,而本工具需要你告诉它。目录写 `logs/`,文件写 `logs`;同一个字符串加不加斜杠可能得到完全相反的结论。这不是工具的怪癖,而正是当路径尚不存在时 `git check-ignore` 常常给出意外答案的原因。
- ** 的三种形式究竟是什么意思?
- 只有当 `**` 独占一整段路径时才有特殊含义。开头的 `**/foo` 匹配任意深度的 foo,它是不含斜杠的规则本来就有的行为的显式写法。结尾的 `foo/**` 匹配 foo 里的一切,但不匹配 foo 本身,前面那套重新包含的写法之所以成立,靠的正是这一点。位于中间的 `a/**/b` 匹配 a/b、a/x/b 和 a/x/y/b,也就是零个或多个目录。放在其他位置就只是普通的星号:`a**b` 等同于 `a*b`,而单个 `*` 不会跨越斜杠,所以 `src/*.c` 匹配 src/main.c,却不匹配 src/lib/main.c。
- 规则看起来没错,git 却仍然显示文件被修改。
- .gitignore 只对 git 尚未跟踪的文件起作用。文件一旦被提交过,后来再加规则也不会改变什么:git 依然报告它的改动,依然把它提交进去。要先用 `git rm --cached 路径` 取消跟踪(工作区里的文件会保留),并提交这次删除;从下一次提交开始,忽略规则才说了算。本工具回答的是未跟踪文件的问题,与 `check-ignore` 相同,所以一条在这里显示为被忽略的路径,只要还在索引里,就仍会出现在 `git status` 中——两者不一致时,这是第一个该检查的地方。
- 有多个 .gitignore 时以哪个为准?
- git 按固定顺序读取多个来源,越具体的越优先:先是命令行给出的规则,然后是各个 .gitignore 文件,其中更深目录里的文件会覆盖上层的文件,接着是不会被共享的仓库本地规则 .git/info/exclude,最后是 core.excludesFile 指定的全局文件。在同一个文件内部,由最后一条匹配的行决定。本工具只模拟一份 .gitignore,因此如果它的结论与你的仓库不一致,多半是子目录里的 .gitignore、info/exclude 中的某一条或你的全局文件在起作用;在那里运行 `git check-ignore -v`,来源那一列会告诉你是哪个文件。
相关工具
EditorConfig 测试器
粘贴 .editorconfig 和一组文件路径,查看每个文件最终解析出的属性,以及每个值由哪一小节、哪一行决定。
.gitignore 生成器
勾选你使用的语言、框架、编辑器和操作系统 — 得到一个可直接放进新仓库的整合 `.gitignore`。
Glob 模式测试器
在浏览器中针对 glob 模式(*、**、?、[...]、{a,b})测试文件路径。
WebAssembly 模块检查器
在浏览器中解析 .wasm 文件:各段大小、带完整类型的导入与导出、内存页数、start 函数,以及 name 与 producers 自定义段。
JSON Schema 校验器
在浏览器中用 JSON Schema 校验 JSON 文档:每条错误都给出 JSON 指针、对应行号和失败的关键字。
补丁 / diff 检查器
解析统一格式 diff 或 .patch 文件:改动了哪些文件、每个文件的增删行数,以及会让 git apply 失败的损坏 hunk。