git clean -fdx vs -fdX: Removing Untracked Files
git clean -fd removes untracked files and directories; adding -x also removes ignored files (build output), while -X removes only the ignored ones, leaving new source untouched.
Resetting a runner workspace means deleting untracked junk, but the difference between lowercase -x and uppercase -X decides whether you wipe build caches or only them. Always dry-run with -n first.
What it does
git clean deletes untracked files. -f is required to actually delete (force). -d also recurses into untracked directories. -x removes files that .gitignore would normally protect (node_modules, dist), giving a pristine tree. -X removes only ignored files and keeps untracked, not-yet-added source. -n shows what would be deleted without deleting.
Common usage
git clean -n -d # dry run: list what would go
git clean -fd # remove untracked files + dirs
git clean -fdx # also remove ignored (full reset)
git clean -fdX # remove ONLY ignored files
# combine with hard reset for a pristine workspace
git reset --hard && git clean -fdxOptions
| Flag | What it does |
|---|---|
| -f / --force | Actually delete (required unless clean.requireForce=false) |
| -d | Recurse into untracked directories |
| -x | Also remove ignored files (use the full ignore set) |
| -X | Remove ONLY ignored files, keep other untracked files |
| -n / --dry-run | List what would be removed without removing |
| -e <pattern> | Add an exclude pattern on top of .gitignore |
In CI
On persistent or self-hosted runners, git clean -fdx between jobs prevents stale artifacts from leaking into a build, but it also blows away caches, so weigh -fdx (full reset) against -fdX (drop only ignored build output). git reset --hard does not touch untracked files; pair it with git clean to truly reset. Dry-run with -n in a new pipeline before trusting -f.
Common errors in CI
"fatal: clean.requireForce defaults to true and neither -i, -n, nor -f given" means you forgot -f. "Cowardly refusing to clean the current working directory" can appear in edge cases; run from the repo root. Surprise deletion of needed files usually means -x was used where -X (ignored only) was intended.
Using this in CI
CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # history, tags, and git describe all need this
- run: |
git rev-parse --is-shallow-repository # expect false
git rev-parse --abbrev-ref HEAD # prints HEAD when detached