.gitignore 不生效:规则根本没够到索引
check-ignore -v 三十秒定乾坤——打印出规则就是规则出了问题,一片安静就是文件早被跟踪了,rm --cached 一锤定音。
■ space · 散文泳道
.gitignore 「不生效」几乎总是意味着 文件已经被跟踪 ——进了索引的文件,对你写的任何规则都免疫。
git check-ignore -v <path> 一锤定音: 打印出规则 = 规则出了问题; 一片安静 = 已被跟踪,任何规则都不适用。
修法: git rm --cached <path>,commit——从那个 commit 起,规则就生效了。
两扇门
一条命令,两种结局—— git check-ignore -v会把你送进其中一扇:
门 1 · 它打印出一条规则
$ git check-ignore -v debug.log
.gitignore:3:*.log debug.log
有规则在起作用—— 但不是对的那条,或者作用域不对。问题出在 .gitignore 文件里:规则顺序、取反陷阱,或者这条路径归哪个 ignore 文件管。
门 2 · 安静
$ git check-ignore -v src/.env
$ # (nothing — no rule applies)
文件其实已经被跟踪了。 先用 git ls-files --error-unmatch <path>,再 git rm --cached <path> 并把这次删除提交。安静本身就是诊断结论。
退出码可以写进脚本:0 = 被忽略,1 = 未被忽略——git check-ignore -q debug.log && echo ignored || echo tracked-or-unruly
标本——一份 .gitignore,逐行看
带注释的取反陷阱。为什么 !build/keep.me 救不回那个文件:
build/整个目录直接忽略——git 再也不会往里看!build/keep.me死信:被排除的目录里,文件无法重新纳入build/*正解——忽略内容,别忽略目录本身!build/keep.me这下活了:父路径可以走通,例外生效*.log 再 !important.log最后匹配的规则赢——规则后面的取反把这一个文件重新纳入完整的病因表
| 症状 | 真实病因 | 修法 |
|---|---|---|
被忽略的文件仍然出现在 git status | 在规则之前就提交了——在索引里 | git rm --cached + commit |
git add . 一直把它重新加回来 | 同上:跟踪压过忽略 | 批量: git rm -r --cached . → git add . |
!build/keep.me 救不回那个文件 | 父目录被排除——git 整个跳过 | build/* + !build/keep.me |
| 更靠后的规则盖过你的 | 最后匹配的规则赢 | 调整顺序,或者用 check-ignore -v |
| 规则对同事有效,对你无效(或者反过来) | .gitignore 嵌套 / exclude / 全局配置对不上 | 对照下面的作用域表 |
| 忽略之后 VS Code 仍显示它被修改 | 已被跟踪——或者 SCM 视图没刷新 | git rm --cached;先重载窗口 |
| 想改得安静,文件保持被跟踪 | 有意为之的本地分叉 | git update-index --skip-worktree |
三个作用域
规则可以住在三个地方,「对同事有效、对我无效」几乎总是作用域对不上:
.gitignore在仓库里 ——已提交,所有人共享。构建产物和依赖目录的默认住所。.git/info/exclude——每个克隆独立,从不提交。存放你这个 checkout 里个人草稿文件的地方。- 你的全局 ignore 文件(
core.excludesFile)——每台机器一份,覆盖所有仓库。经典归宿是.DS_Store和编辑器掉的各种渣。
读 check-ignore -v 的输出会直接点名来源:哪个 ignore 文件,然后 line-number:pattern,然后是路径——所以当一条意外规则胜出时,赢家会自己报名字。
验证:git check-ignore -v debug.log → .gitignore:3:*.log debug.log
取消跟踪,一步一步来
# untrack one file (the local copy survives — --cached touches the index only)
git rm --cached .env
git commit -m "stop tracking .env"
# verify the ignore rule now applies
git check-ignore -v .env
从这个 commit 起, .gitignore 接管了这条路径:改动不再出现在 git status, git add . 也不会再把这个文件捡回去。
如果那是个秘密,取消跟踪不是解药。文件还留在 历史 ——把它从最新 commit 里删掉远远不够。轮换凭证才是真治;改写历史只是化妆。
两扇门到此为止 · 没有任何 fetch · 全程本地