Stashing untracked and ignored files Jump to heading

A plain git stash saves changes to tracked files only. New files you have not added yet stay in the working tree, which surprises people: they stash, switch branches, and find their new module sitting there on the other branch, or they stash to get a clean tree and the build still picks up the new file. -u (--include-untracked) includes new files. -a (--all) goes further and includes ignored files too β€” build output, dependency directories, local configuration. That second option is almost never what you want and is a common way to stash gigabytes of node_modules or a .env file full of credentials. This page explains the three modes and how to use them safely, within stashing and work-in-progress recovery.

When to use this approach Jump to heading

  • You stashed, and new files you created were left behind.
  • You need a truly clean working tree, including new files, for a test or a branch switch.
  • Someone suggested git stash -a and you want to know what it does before running it.
  • You are deciding between stashing and other ways to park work, as in stash vs worktree vs WIP commit.

Step 1 β€” Know what each mode includes Jump to heading

There are three classes of file: tracked (Git knows them), untracked (new, not ignored), and ignored (matched by .gitignore). Each stash mode takes a different set.

What each stash mode includesA plain stash takes only changes to tracked files. With -u it also takes new untracked files. With -a it takes ignored files as well, such as build output, dependency directories and local secrets files, which is rarely wanted.tracked + untrackedignored (build, deps, .env)git stashtracked onlynot includedgit stash -ubothnot includedgit stash -abothincluded-u is the mode most people actually want; -a is for exceptional cases
git status --short --ignored
#  M src/export/schedule.py        tracked, modified
# ?? src/export/prototype.py       untracked
# !! node_modules/                  ignored
# !! .env                           ignored

Step 2 β€” Include new files with -u Jump to heading

-u stashes tracked changes and untracked files, then removes the untracked files from the working tree. After it, git status shows a clean tree apart from ignored files.

git stash push -u -m "export prototype, including new files"
git status --short                 # clean
ls src/export/prototype.py 2>/dev/null || echo "new file stashed"

Untracked files are stored in a third parent of the stash commit, which is why git stash show does not list them by default.

git stash show --include-untracked stash@{0}      # Git 2.32+
git show --stat 'stash@{0}^3'                     # any version: the untracked-files commit

Step 3 β€” Avoid -a unless you mean it Jump to heading

-a stashes and then deletes ignored files: your dependency directory, build output, editor settings, local environment files. Restoring them means applying a potentially huge stash; and until you do, the project will not build.

# Check the size of what -a would take before ever running it
git status --short --ignored | awk '$1=="!!"{print $2}' | xargs du -sh 2>/dev/null | sort -h | tail
What git stash -a would sweep up in a typical projectAn illustrative web project: the source changes being stashed are tiny, but -a would also take the dependency directory, build output and local environment file, making the stash hundreds of times larger and deleting things the project needs to run.megabytes included in the stash (illustrative)source changes0.4 MBnode_modules/612 MBdist/38 MB.env + local config0.01 MB, secretssize is the visible cost; the .env file in a stash is the hidden one

⚠️ SAFETY WARNING: git stash -a deletes ignored files from the working tree after stashing them, including dependency directories and local secrets files. The stash also keeps a copy of those secrets in your repository’s object store, where tools that copy or upload .git can pick them up. If you ran it by accident, git stash pop restores everything; if you want to discard the stash, run git stash drop and then git gc --prune=now to remove the stored copy.

Step 4 β€” Clean without stashing when you do not need the files back Jump to heading

Sometimes the goal is a clean tree and the new files are disposable β€” generated test output, scratch files. Then git clean is the right tool, not a stash. Always run it with -n first.

git clean -n                # list untracked files that would be deleted
git clean -n -d             # include untracked directories
git clean -f -d             # delete them
git clean -n -X             # only ignored files (e.g. stale build output)

⚠️ SAFETY WARNING: git clean -f permanently deletes untracked files; they are not stored anywhere in Git and cannot be recovered with the reflog or fsck. Always preview with -n. If any listed file might be wanted, stash it with -u instead.

Step 5 β€” Restore untracked files cleanly Jump to heading

Popping a stash that contains untracked files fails if a file with the same path now exists in the working tree β€” Git will not overwrite it. Move the conflicting file aside, then pop.

git stash pop
# error: src/export/prototype.py already exists, no checkout
mv src/export/prototype.py /tmp/prototype.py.new
git stash pop
diff /tmp/prototype.py.new src/export/prototype.py
Choosing how to handle new filesIf you want the new files back later, stash with -u. If they are disposable, preview and remove them with git clean. If you need ignored files stashed too, check the size first and use -a only deliberately.What should happen to the new files?keep for latergit stash -urestored on popthrow awaygit clean -n, -fnot recoverableignored ones toogit stash -acheck size firstthe cleanest working tree is not always worth a stash

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

Why aren’t untracked files in git stash show output? Jump to heading

They are stored in a separate parent commit of the stash, and show only diffs against the first parent by default. Use --include-untracked (Git 2.32+) or inspect stash@{n}^3 directly.

Can I make -u the default? Jump to heading

Not through a dedicated setting. An alias such as git config --global alias.su 'stash push -u' gives you a short command that always includes untracked files.

Does stashing untracked files respect .gitignore? Jump to heading

Yes. -u takes only untracked files that are not ignored. Ignored files are taken only with -a.