.gitignore只对从未被git追踪的文件生效;已提交文件必须先用git rm --cached解除追踪,再写入规则并提交,才能真正忽略。

.gitignore 对已提交文件完全无效
直接说结论:.gitignore 只对「从未被 Git 追踪过」的文件起作用。如果一个文件已经执行过 git add 和 git commit,哪怕你立刻在 .gitignore 里加上规则,Git 仍会继续追踪它——不会自动停止跟踪,也不会在下次 git status 中隐藏它。
这是最常被误解的一点:很多人删掉 .gitignore 里的某条规则,以为文件就“重新被纳入管理”了;或者新增一条规则,以为刚 git add 错的配置文件就“被忽略”了——其实都不成立。
- 已提交的文件 → 必须先用
git rm --cached手动解除追踪 - 解除后该文件变成「未跟踪状态」→ 此时
.gitignore规则才开始生效 - 若想保留本地文件(比如
.env),一定加--cached,不加会连本地磁盘文件一起删
如何安全地忽略已提交但不该提交的文件
典型场景:误提交了 .idea/、target/、node_modules/ 或 .env,现在想让它彻底从 Git 历史中“消失”,但又不想删掉自己电脑上的文件。
分三步操作(缺一不可):
- 确认文件当前是否已被追踪:
git ls-files | grep "pattern"(例如git ls-files | grep ".idea") - 解除追踪(保留本地文件):
git rm -r --cached .idea/(目录加-r;单个文件省略) - 把规则写进
.gitignore:echo ".idea/" >> .gitignore,再git add .gitignore - 最后提交:
git commit -m "ignore .idea directory"
注意:git rm --cached 不会删除工作区文件,但会把它从暂存区移除;后续 git status 会显示为 “deleted”,这是正常现象——因为 Git 已不再管它了。
/ 开头和 **/ 的区别决定忽略范围
很多规则看似相似,实际匹配行为天差地别。关键看路径开头有没有 /,以及有没有用 **。
-
dist/→ 匹配所有名为dist/的目录,无论在哪层(src/dist/、build/dist/都中招) -
/dist/→ 只匹配项目根目录下的dist/(src/dist/不受影响) -
**/log→ 匹配任意深度的log目录或文件(log、a/log、a/b/c/log) -
log→ 匹配所有叫log的文件或目录(包括alog、logging,因为*是前缀通配) -
!src/main/resources/config.yaml→ 要放在src/**或src/规则之后才有意义,否则没东西可“反忽略”
常见翻车点:build(没加 /)会意外匹配 rebuild.sh;**/node_modules 比 node_modules/ 更彻底,能覆盖嵌套的 yarn workspace 子包里的 node_modules。
全局忽略 vs 本地 exclude vs 仓库 .gitignore
Git 实际按固定顺序检查三类忽略规则,优先级从高到低:
-
.git/info/exclude:仅当前仓库生效,不提交,适合放个人临时文件(如*.swp、~备份) -
~/.gitignore_global(需git config --global core.excludesfile指定):影响你机器上所有 Git 仓库,适合操作系统级文件(.DS_Store、Thumbs.db) -
.gitignore(仓库根目录):团队共享,必须提交,用于项目通用产物(target/、__pycache__/)
查当前生效的全局路径:git config --get core.excludesfile;如果返回空,说明没设全局忽略文件。不要把本该全局的规则(如 .DS_Store)塞进每个项目的 .gitignore,既重复又难维护。
真正容易被忽略的是:一旦某条规则在更高优先级的文件里被匹配并忽略,低优先级文件里的同名 ! 否定规则就失效了——比如全局忽略了 *.log,你在项目 .gitignore 里写 !server.log 是没用的。











