Why does git stash leave new untracked files behind, and which flags include them?
answer
- Depends on what Git already knows about
- The index defines what counts
- Two flags, increasing reach
- One adds new files, one also adds ignored ones
- -u is routine, -a sweeps build output
basics
~20 sBy default git stash only records tracked content — index changes and modifications to files Git already knows. Untracked files are invisible to it. Use -u (--include-untracked) to add untracked files, or -a (--all) to include ignored files too.
solid answer
~40 sA stash is built from what Git tracks: the index and working-tree modifications to files already in `HEAD`. A brand-new file has never been added, so it is not part of that state and stays sitting in your working tree after the stash — which is why you can stash, think you are clean, and still have a build break on a leftover new file. `git stash push -u` (long form `--include-untracked`) stashes untracked files as well and removes them from the working tree, restoring them on apply. `git stash push -a` (`--all`) goes further and includes ignored files too. I use `-u` deliberately and `-a` almost never: `--all` will happily sweep up build output and dependency directories, which makes the stash enormous and its restore surprising.
code
console · 10 lines$ git status --short
M src/main.py
?? src/parser.py
$ git stash push
Saved working directory and index state WIP on feature: 9a3f21c Add parser skeleton
$ git status --short
?? src/parser.py
$ git stash push -u -m "parser wip"
$ git status --short
$go deeper
Remember that a plain git stash leaves brand-new files in your working tree, and that -u includes them. Check git status --short for ?? lines before assuming you are clean.
Explain it in terms of the index: a stash records tracked content, so untracked files are outside the recorded state. Know that -u also removes them from the working tree and -a additionally covers ignored files.
Show the operational consequence — leftover untracked files breaking a build or blocking a checkout — and why --all is a hazard around build output and dependency directories. Mention pathspec-scoped stashes as the precise alternative.
Consider what routinely lands in untracked and ignored space in your repository, and whether the ignore rules and build layout are making stash, checkout and clean riskier than they should be for everyone.
## What "tracked" means here Git's notion of your current state is the index plus `HEAD`. A file is **tracked** if it is in the index — that is, Git has been told about it via `git add` at some point. A file you have just created and never added is **untracked**: Git sees it on disk and lists it under "Untracked files" in `git status`, but it is not part of the recorded state. `git stash push` records the difference between your working tree/index and `HEAD`. Untracked files are not a difference *from* anything Git recorded — they are simply outside the picture. So the default stash ignores them and leaves them exactly where they are. ## Why this bites The usual scenario: you add a new source file plus edits to three existing ones, stash to look at a colleague's branch, and the build fails in a way that makes no sense. The three edits went into the stash; the new file did not, so you are compiling someone else's branch with your unreferenced new file sitting in the tree. Worse, if that branch already has a file at that path, checkout may refuse or the file may collide. ## The flags ``` git stash push -u # --include-untracked git stash push -a # --all: untracked plus ignored ``` - **`-u` / `--include-untracked`** stashes untracked files along with tracked changes and **removes them from the working tree**, so you really are clean afterwards. Restoring the stash recreates them. - **`-a` / `--all`** adds files matched by ignore rules — `.gitignore`, `.git/info/exclude`, and so on. `-u` is the one you want in daily use. `-a` is a specialist tool: ignored paths are typically build output, virtualenvs, dependency trees and local config, so `--all` can produce a huge stash, delete your build cache, and then restore it later over whatever is there. Reach for it only when you genuinely need the ignored files preserved, for example before a destructive experiment in a directory you cannot regenerate. ## Restoring untracked files When you apply or pop, the untracked portion is written back into the working tree as untracked files again. If a file now exists at the same path, the restore fails rather than clobbering it — Git refuses to overwrite an existing untracked file. That is a safety feature, but it means you may have to move the colliding file aside and retry. ## Scoping a stash to specific paths Related and often confused: `git stash push` accepts a pathspec, so you can stash only part of your work. ``` git stash push -m "only the parser" -- src/parser/ ``` Combined with `-u`, the pathspec applies to untracked files as well, which is a much safer way to sweep in new files than `--all` across the whole tree. ## Making it visible Before you rely on being clean, check: ``` git status --short ``` Lines starting with `??` are untracked; those are exactly the files a default stash will leave behind. After `git stash push -u` they should be gone. To see whether an existing stash contains untracked files, `git stash show` on the entry shows the tracked diff; a stash created with `-u` also carries a separate untracked-files portion, so a plain `show` can under-report what will come back. ## The configuration angle There is no config that makes `-u` the default; it is a per-invocation choice. If you want the behaviour every time, an alias is the honest way to get it — and it keeps the flag visible to anyone reading your setup rather than silently changing what a familiar command does. ## What interviewers are checking That you understand tracked versus untracked as a property of the index, not a vague "new file" notion; that you know `-u` exists and what it does to the working tree; and that you can articulate why `-a` is dangerous rather than just "more thorough". A candidate who says "I stash with `-u` because a default stash leaves new files behind and that has broken builds for me" has answered it from experience.
- What happens on restore if a file with the same path as a stashed untracked file already exists?Git refuses to overwrite an existing untracked file and the restore fails rather than destroying it. Move or delete the colliding file, then apply again. This is the same protection that stops checkout from clobbering untracked files, and it is why a stash restore can fail even when nothing has been committed on the branch.
- When is `git stash push -a` actually justified?When the ignored files themselves matter and cannot be cheaply regenerated — a local config file, generated artefacts you are mid-way through comparing, a data directory. Otherwise it makes the stash enormous, wipes your build output, and restores it later over whatever is there. For the common case of new source files, `-u` is what you want.
- How do you stash only some of your changes rather than the whole tree?`git stash push` takes a pathspec: `git stash push -m "parser only" -- src/parser/` shelves just that subtree and leaves the rest of your work in place. For hunk-level selection within files, `git stash push -p` walks you through each hunk interactively, the same selection interface as interactive staging.
saying these in an interview costs you the question
- Assuming stash captures everything in the directory
- Thinking untracked means unstaged
- Using --all routinely and stashing build output
- Believing a default stash leaves you truly clean
- Expecting a restore to overwrite an existing untracked file