In Git, what does git clean -fdx remove, and why preview it with -n first?
answer
- Reset handles tracked files; something else handles the rest
- One letter makes it descend into directories
- One letter makes it stop honouring your ignore rules
- Force is mandatory by default
- Nothing deleted was ever an object
basics
~20 sgit clean -fdx deletes untracked files (-f), descends into untracked directories (-d), and also removes files your ignore rules exclude (-x) — build output, local env files, dependency folders. Nothing it deletes is in Git, so -n previews the list first.
solid answer
~40 s`git clean` deletes **untracked** files from the working tree — the ones `git reset --hard` leaves alone because Git never tracked them. `-f` is mandatory by default (`clean.requireForce` is true), `-d` makes it recurse into untracked directories, and `-x` additionally ignores your `.gitignore` rules so ignored artifacts go too. `git clean -fdx` therefore returns the working tree to a pristine-checkout state: `build/`, `node_modules/`, `.env` and any local scratch file are all gone. Since none of that content is in the object database, there is no reflog, no `ORIG_HEAD`, no `git fsck` recovery — deletion is final. That is why you run `git clean -ndx` (or `-n` with the same flags) first: `--dry-run` prints exactly what would be removed so you can spot the untracked file you actually wanted.
code
console · 6 lines$ git clean -ndx
Would remove build/
Would remove node_modules/
Would remove .env
Would remove notes.txt
$ git clean -fdxgo deeper
Know that git clean deletes untracked files, that -f is required, and that -n shows you the list before anything is removed.
Be precise about each flag: -d for directories, -x to also sweep ignored artifacts, -X for ignored only, and why the pairing with reset --hard produces a fresh-checkout state.
Demonstrate the operational instinct: dry-run first, know that ignored local credentials and fixtures die under -x, and that nothing clean removes is recoverable through Git.
Own the policy angle — when a build depends on a clean tree, whether cleanup belongs in a script or a fresh checkout, and how ignore rules that hide real local state make -x an organisational hazard.
## What clean is for `git reset --hard` restores every **tracked** file to a commit's content, but it does not touch files Git has never seen. A tree that also carries stale build output, a local `.env`, generated code, or a half-finished scratch file is still not a clean checkout. `git clean` is the command that removes untracked content, and it is the one people reach for when a build fails only on their machine. ## The flags that matter - **`-n` / `--dry-run`** — print what would be deleted and delete nothing. Always the first invocation. - **`-f` / `--force`** — actually delete. Required because `clean.requireForce` defaults to true; without `-f`, `-n` or `-i` the command refuses to run. - **`-d`** — also recurse into and remove untracked *directories*. Without it, an entirely untracked directory is left in place. - **`-x`** — do not honour ignore rules. Normally clean skips ignored paths (`.gitignore`, `.git/info/exclude`, the global excludes file); `-x` includes them, which is what sweeps away `build/`, `target/`, `node_modules/` and local dotfiles. - **`-X`** (capital) — the inverse: remove **only** ignored files, keeping other untracked ones. Useful for "delete build artifacts but keep my new source file". - **`-i` / `--interactive`** — walk the candidate list and choose. - **`-e <pattern>` / `--exclude=<pattern>`** — add an exclusion for this run, e.g. keeping `.env` while sweeping the rest. So `git clean -fdx` = force, include directories, include ignored files: the strongest ordinary form. Combined with a reset it is the standard "make this look like a fresh clone" recipe: `git reset --hard && git clean -fdx` ## Why the dry run is not optional Everything clean deletes was, by definition, never committed. There is no blob in the object database, so none of Git's safety nets apply: not the reflog, not `ORIG_HEAD`, not `git fsck --lost-found`. The file is simply unlinked from disk. In practice `-x` is where people get hurt: a local `.env` with credentials, a downloaded fixture, an uncommitted migration, a lockfile someone edited by hand — all ignored, all destroyed. `git clean -ndx` prints one `Would remove …` line per candidate and costs a second. ## Nested repositories Git refuses to delete an untracked directory that is itself a Git repository (it contains a `.git` directory) unless you give `-f` **twice** (`-ff`). That protects vendored checkouts and stray clones from being wiped by a routine cleanup. If a cleanup script mysteriously leaves one directory behind, this rule is usually why. ## Interview framing The strong answer distinguishes the three commands that all sound like "undo": - `git restore <path>` — put a tracked file back from the index or a commit. - `git reset --hard` — put HEAD, the index and all *tracked* files back to a commit. - `git clean` — delete *untracked* files that none of the above will touch. And then closes with the safety point: only clean deletes content Git has never stored, so it is the only one of the three with no recovery path at all.
- How do you sweep build artifacts but keep an untracked file you are still working on?Two options. `git clean -fdX` (capital X) removes only ignored files, so a brand-new untracked source file survives. Or exclude it for one run: `git clean -fdx -e .env`. Interactive mode, `git clean -id`, lets you filter the candidate list by hand when the distinction is not expressible as one pattern.
- Why did git clean skip a directory even with -fd?Almost certainly because that directory is itself a Git repository — it contains a `.git` directory. Git refuses to delete nested repositories with a single `-f`, so a stray clone or vendored checkout is not wiped by routine cleanup. Repeating the flag, `git clean -ffd`, overrides that protection.
saying these in an interview costs you the question
- Assuming git reset --hard already removes untracked files
- Thinking -x means 'exclude ignored files' rather than include them
- Believing the reflog can restore files git clean deleted
- Expecting -f alone to remove untracked directories
- Claiming git clean removes tracked files that were modified