.gitignore 写了规则,为什么文件还是被提交上去?

3 个讲解板块 · 关联 2 款站内工具 · 内容最后核对 2026-10-10

忽略规则只管「还没被跟踪」的文件。已经进过版本库的文件,加多少条规则都拦不住,得先让它从跟踪列表里退出来。

直接答案

决定性的前提是:忽略规则只对「未跟踪」的文件生效。只要一个文件被 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。若发现错误,欢迎通过页脚反馈入口告知。