.gitignore 写了规则,为什么文件还是被提交上去?
忽略规则只管「还没被跟踪」的文件。已经进过版本库的文件,加多少条规则都拦不住,得先让它从跟踪列表里退出来。
决定性的前提是:忽略规则只对「未跟踪」的文件生效。只要一个文件被 git add 过并且提交过,它就已经在版本库里了,.gitignore 里的任何一行都影响不到它,改动它照样会出现在变更列表里。
要让已经入库的文件重新被忽略,分两步:先 git rm --cached <文件> 把它从跟踪列表里移出去(这一步不动工作区里的文件),再把这个移除操作提交一次。之后规则才会开始对它生效。
第二条常见原因是规则的写法。前导斜杠、尾随斜杠、星号的位置都会改变匹配范围;规则是从下往上匹配、最后命中的那条说了算;而已经被整体排除的目录,内部的「反选」写法(感叹号开头)不会生效。
.gitignore 是版本控制里最容易被误解的一个文件。它的名字让人觉得「这是我让 Git 无视的文件清单」,但它真正表达的是一句更窄的话:「这些文件请当作不存在,除非你已经跟踪了它们」。
这一篇把这个前提讲透,并给出「怎么查、怎么改、怎么防」的完整路径。所有规则判断都可以用一条命令自证,不必靠猜。
1先分清三种状态
同一个文件在不同状态下的表现完全不同。判断规则为什么「不管用」,第一步是确认它现在处于哪个状态。
| 文件状态 | 忽略规则管用吗 | 表现 |
|---|---|---|
| 从未被跟踪 | 管用 | 不出现在变更列表里,规则一行就能拦住 |
| 已暂存但未提交 | 基本管用 | 用 git rm --cached 撤出暂存即可重新被忽略 |
| 已提交进版本库 | 完全不管用 | 必须 git rm --cached 并提交这次移除,之后规则才生效 |
把规则当成「入场券检查」,检票口只管第一次进场的人。已经进过一次的,门口拦不住。
2三步排查法
每条规则都问一句「这条规则匹配到这个路径了吗」,Git 自带一条命令可以直接给出答案,不用试错。
- 先看规则有没有选中它
- 执行
git check-ignore -v <路径>,会打印命中的规则行号、文件名与规则原文;没有输出就说明这条路径没被任何规则命中 - 再看文件是不是已被跟踪
- 执行
git ls-files --error-unmatch <路径>,能列出就说明它已在版本库里,规则自然失效,需要用移除缓存的方式处理 - 最后看有没有更高优先级的规则
- 同一份配置里,规则从下往上匹配、最后命中的生效;全局忽略文件的优先级低于仓库内的规则
这两条命令把「规则问题」和「状态问题」彻底分开。多数人卡住是因为在用规则的办法修状态的问题。
3路径写法:三种符号改变一切
同一个名字,加不加斜杠、加不加星号,匹配的范围差得很远。
| 写法 | 匹配范围 | 容易踩的坑 |
|---|---|---|
build/ | 任意层级的名为 build 的目录 | 只匹配目录,同名的普通文件不受影响 |
/build | 仅仓库根目录下的 build | 写成了带斜杠的目录形式就不再匹配同名的普通文件 |
*.log | 任意层级的 .log 文件 | 星号不跨目录分隔符,logs/*.log 只覆盖同级 |
!keep.txt | 把前面排除掉的文件重新选回来 | 父目录已被整体排除时这条不起作用,因为 Git 不会进入被排除的目录 |
反选规则要写在排除规则之后才有效,而且必须保证它的父目录没有被整体排除。
顺着这个问题往下用
全部工具总览 →相关疑问
为什么我加了规则,文件还是出现在变更列表里?
因为它已经被跟踪了。规则只影响未跟踪的文件,先确认状态,再用移除缓存的方式处理它。
用 git rm --cached 会把本地文件删掉吗?
不会。加上 --cached 参数后只从版本库里移除记录,工作区里的文件原样保留,这也是它与直接删除的关键区别。
反选规则为什么没反应?
最常见的原因是它的父目录被整体排除了。Git 不会为了找反选目标而深入一个已被排除的目录,需要把父目录的排除改得更精细。
团队里每个人都有一套忽略规则怎么办?
仓库内的规则优先于个人全局规则,需要团队统一的写进仓库;只影响自己机器的(如编辑器临时文件)放全局忽略文件,不要提交进仓库。
继续看:相关问题与资料
全部问题解答 →内容说明:本页针对具体使用问题作答,方法步骤与数值由本站自行整理与复算,事实性内容以对应官方规范与文档为准。内容最后核对日期:2026-10-10。若发现错误,欢迎通过页脚反馈入口告知。
速查在线工具箱