■ 空间 · 散文道

■ 先看答案

git clean -nd 预览,git clean -fd 删除——clean 的删除是永久的;垃圾站从不经手.

clean 什么都没删?文件位于 未跟踪的目录(加上 -d)),或者属于 被忽略的文件(加上 -x).

想之后还能找回? git stash -u,清理前先 ——之后没有撤销,-f.

波及范围

树里的每个文件都住在三个区域中的一个——而 clean 的每个旗标恰好只够到一圈:

第四个箱子是陷阱:被忽略的文件根本不以 ?? 出现——普通 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 ——提交前看一眼,清理前也看一眼。旗标一个个说:

“CLEAN 什么都没删”——三种原因

  1. 文件在未跟踪的目录里。 只用 -f,git 只删散文件,到目录就停——甚至提示 Would remove build/,真跑时并不删除。-d: git clean -fd.
  2. 文件被 gitignore 了。 node_modules/, dist/, .venv/ ——被忽略的路径对普通 clean 隐形;dry run 也不会列出。要显式点名: git clean -fdx.
  3. 嵌套的 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永远别跑的东西

  1. 永远别盲目地跑 git clean -fdx ——monorepo 或 workspace 里尤其使不得。 它会删掉每个被忽略的目录——所有 node_modules,每个 virtualenv,每个本地 .env ——整棵树里的。.env 可能根本无法恢复。
  2. 别把 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 clean · dry-run 仪式 · 带 -x 识得 .gitignore。 首发于2026-09-09,条目于2026-10-04刷新。每一条命令、每一个“什么都没删”的原因,都是 git clean 的文档化行为,出自真实清理的亲敲——git status --short 示例就是每个仓库真实打印出来的形状。

clean 页到此为止 · 未拉取任何东西 · 一切本地