■ 空间 · 散文道
git clean -nd 预览,git clean -fd 删除——clean 的删除是永久的;垃圾站从不经手.
clean 什么都没删?文件位于 未跟踪的目录(加上 -d)),或者属于 被忽略的文件(加上 -x).
想之后还能找回? git stash -u,清理前先 ——之后没有撤销,-f.
波及范围
树里的每个文件都住在三个区域中的一个——而 clean 的每个旗标恰好只够到一圈:
clean 从不碰它们。编辑: git restore。删除: git rm.
由 clean -f 触达,还有 -d(作用于未跟踪目录内部)
只有借 -x(或 -X,用于仅忽略项)
第四个箱子是陷阱:被忽略的文件根本不以 ?? 出现——普通 clean 会悄悄跳过它们,这就是它“什么都没删”的原因
「未跟踪」是什么意思
未跟踪的意思是:git 在磁盘上看得见这个文件,但从没人叫它去跟踪——不在索引里,没有提交历史。 git status 把一切分箱归类,而每箱都要不同的删除工具:
$ git status --short
M src/app.ts # modified: tracked, changed
?? notes.txt # untracked: new file git doesn't know
?? build/ # untracked directory: entirely new to git
已跟踪但被改动的文件用 git restore 回滚,或提交掉—— git clean 不会碰它们。只有 ?? 行是 clean 的地盘。如果你真正的问题是某个 已跟踪 文件本不该被提交,那清理用错了工具——那是 git rm --cached 的活儿,或者 reset 掉上一个提交。
仪式
# 1. see exactly what will be deleted (dry run — deletes nothing)
git clean -nd
# Would remove:
# notes.txt
# build/
# 2. confirm nothing precious is in the list, then delete for real
git clean -fd
verify: git clean -nd → 会打印 “Would remove notes.txt build/” · -fd 之后:git status --short 再无任何 ?? 行
值得复制的习惯:把 git clean -nd 当成 git diff ——提交前看一眼,清理前也看一眼。旗标一个个说:
-f/--force——必需。真正执行删除未跟踪文件。没有它 git 会拒绝并打印警告——刻意设的安全栏。-d——递归进入未跟踪 目录。光溜溜的-f只删顶层的未跟踪文件,并列出它拒绝进入的目录。-n/--dry-run——先看看 将会 删除哪些。永远第一个跑。-x——一并删除 被忽略的 文件(node_modules,构建产物,.env).-X——删除 仅 被忽略的文件,保留未跟踪但未被忽略的。-i——交互模式;dry-run 列表很长时好用。-e <path>——排除——“除 notes.txt 外全清”就是git clean -fd -e notes.txt.
“CLEAN 什么都没删”——三种原因
- 文件在未跟踪的目录里。 只用
-f,git 只删散文件,到目录就停——甚至提示Would remove build/,真跑时并不删除。-d:git clean -fd. - 文件被 gitignore 了。
node_modules/,dist/,.venv/——被忽略的路径对普通 clean 隐形;dry run 也不会列出。要显式点名:git clean -fdx. - 嵌套的 git 仓库或子模块挡路。 git 从不删别的仓库的内容。先妥善移除子模块,或者传
--force两次(git clean -ffd)——优先第一种。
如果 dry run 什么都没列出,但 git status 还是显示 ?? 行,那你八成待错了工作树—— git rev-parse --show-toplevel,并确认你在打算清理的那个仓库里。
只清一个目录
传一个路径来限定 clean 的范围——其余一切不碰。路径相对当前目录:从仓库根目录跑,范围就是整个仓库;从子目录跑,就是那棵子树:
git clean -fd build/ # only inside build/
git clean -fd src/generated # one specific tree
移走而不删除
当 dry run 显示你以后可能想要的文件时,别赌——先保住,再清理。 git stash -u 把未跟踪文件搬出工作树但保持可恢复——这才是人们真正想找的「移走而不删除」语义:
# stash untracked files (including ignored with -a) without deleting
git stash push --include-untracked
git clean -fd # tree is clean
git stash pop # bring them back when needed
verify: git stash list → stash@{0} 存着 git stash -u 提走的东西
想要留得下来的预览: git clean -nd > clean-plan.txt。之后没有撤销——git clean -f:删了就是没了——垃圾站从不经手。
CLEAN、RM、RESTORE 对比
| 命令 | 动到谁 | 从磁盘去除 | 适用场景 |
|---|---|---|---|
git clean -fd | 未跟踪文件/目录 | 是 | 删除 git 从未跟踪过的文件 |
git clean -fdx | 未跟踪 + 被忽略 | 是 | 彻底重置,包括 node_modules,构建产物 |
git rm <file> | 已跟踪文件 | 是(进了暂存区) | 删除文件 并 在 git 里记录这次删除 |
git rm --cached <file> | 已跟踪文件 | 否 | 停止跟踪某文件,但留在磁盘上 |
git restore <file> | 已跟踪文件 | 否 | 丢弃本地改动,保留文件 |
一句话规则: clean 管的是 git 不认识的东西;rm 和 restore 管的是它认识的。 混用它们正是丢工作的方式——跑 git clean -fdx 却以为它像 git restore.
08永远别跑的东西
- 永远别盲目地跑
git clean -fdx——monorepo 或 workspace 里尤其使不得。 它会删掉每个被忽略的目录——所有node_modules,每个 virtualenv,每个本地.env——整棵树里的。.env可能根本无法恢复。 - 别把 force 焊死在 clean 的 alias 里。
git config alias.wipe "clean -fd"效率高,直到你把路径敲错。把 dry run 放在一键可达的位置,做成两条命令的仪式:先预览,再删除。
整套流程,压缩版:
git status --short # what's in the tree?
git clean -nd # preview: what WOULD go?
git clean -fd # delete untracked files + directories
git clean -fdX # (optional) clear only ignored build output
git status --short # confirm: working tree clean
预览、删除、验证——三十秒,零悔意,而 git status 终于又能读到干净的状态了。这个问题的表亲: .gitignore 规则看似无效——如果你的规则被无视,多半是已跟踪文件而非语法问题。而且在 fork sync 前把树收拾干净,能让合并面变小——最便宜的冲突保险。
git status --short 示例就是每个仓库真实打印出来的形状。clean 页到此为止 · 未拉取任何东西 · 一切本地