Git Stash: Untracked Files Follow Branches – CI Failures
git stash ignores untracked files.
- git stash push -m 'description': saves tracked changes with a label
- git stash -u: includes untracked files (new files not yet git add'd)
- git stash pop: restores and removes from stack — use when confident no conflicts
- git stash apply: restores but keeps in stack — use when conflicts are possible
Git stash is a clipboard for your uncommitted work. You're mid-feature when someone drops an urgent bug on your desk. Instead of committing half-finished code or losing your changes, you stash them — Git packs up your working directory changes into a temporary storage area, restores you to a clean HEAD, and waits. Fix the bug, deploy the hotfix, then come back and unstash. Your work resumes exactly where you left it.
git stash shelves uncommitted working directory and index changes into a stack. It is the standard tool for context switching — you stash your current work, switch to a hotfix branch, then unstash when you return. The core failure mode: stash pop deletes the stash even on merge conflicts, leaving you with no backup. Use apply + manual drop when conflicts are possible.
The second failure mode: stash does not include untracked files by default. New files you have not git add'd remain in the working directory when you switch branches. They get committed to the wrong branch. Use stash -u to include them.
Stashes are global to the repository, not scoped to a branch. You can pop a stash made on feature/x onto main. This is sometimes intentional and sometimes a very bad day. Always use stash push -m 'description' to label your stashes — unnamed stashes become mystery boxes within 24 hours.
Basic Stash: Save and Restore Work
The core workflow is three commands. git stash shelves everything in your working directory and index that differs from HEAD. git stash pop restores the most recent stash and removes it from the stack. git stash apply restores without removing — useful when you want to apply the same stash to multiple branches.
One thing that surprises developers coming from other VCS systems: git stash by default only stashes tracked files. If you created a new file that hasn't been git add-ed yet, it won't be stashed. It'll sit there in your working directory when you switch branches, which can lead to unintended commits on the wrong branch. Use git stash -u (or --include-untracked) to include new files.
The stash is a stack — each git stash pushes a new entry. git stash pop pops the top (most recent). This is correct behaviour for the common case but becomes confusion when you stash, do some more work, stash again, and then try to figure out which stash has what.
- Stash is a stack — push adds, pop removes the top
- Stashes are global — not attached to any branch
- You can pop a stash made on feature/x onto main (or any branch)
- This flexibility is powerful but dangerous — always check which branch you are on before popping
Stash Pop vs Apply: When to Use Each
The difference matters more than most tutorials let on.
git stash pop = apply + delete from stack. Use this 95% of the time. The moment you successfully restore your work, the stash entry is gone. Clean, no accumulation.
git stash apply = apply but leave in stack. Use this when: you want to apply the same changes to multiple branches (e.g. a config change you need on both a feature branch and a hotfix branch), or when you're not 100% sure the stash applies cleanly and you want to keep it as a backup while you verify.
There's one critical behaviour difference: if git stash pop encounters a conflict, it still removes the stash from the stack before throwing the conflict. You're now in a conflicted state with the stash gone. This is a Git footgun — you want git stash apply when there's any chance of conflicts, so the stash survives even if the apply fails.
- pop deletes the stash from the stack before you resolve conflicts
- If the apply fails, you have no stash backup — the entry is gone
- Use apply when conflicts are possible. Then drop manually after resolving.
- This is one of the most common Git footguns in production.
Stashing Partial Changes and Specific Files
Sometimes you only want to stash part of your changes — for example, you've been working on two unrelated things in the same branch (happens to everyone, don't judge) and you want to commit one thing cleanly before stashing the other.
git stash push -- <path> stashes only the specified files. Everything else stays in your working directory.
git stash push -p (patch mode) drops you into an interactive hunk-by-hunk selection — exactly like git add -p. You choose yes/no for each chunk. This is powerful but slow for large changesets.
- git stash branch <name> <stash>: creates branch at stash point, applies stash, drops it
- Use when a stash has been sitting for days and has become important work
- Branches are visible in git branch -a. Stashes are only visible in git stash list.
- If a stash survives for weeks, it should have been a branch from the start.
Stash Pop on Wrong Branch: Untracked Files Committed to Main
git stash to save their work — but stash only saves tracked files by default.
3. PaymentRetryService.java was untracked, so it was NOT stashed. It remained in the working directory.
4. Developer switched to main: git checkout main.
5. PaymentRetryService.java (the untracked file) followed them to main.
6. During the hotfix, they ran git add . which staged everything — including PaymentRetryService.java.
7. The file was committed to main with incomplete, non-compiling feature code.
8. CI built from main and failed on the compilation error.git revert <hotfix-commit-hash>.
2. The developer switched back to feature/payment-retry and stashed correctly: git stash push -u -m 'WIP: PaymentRetryService'.
3. Team rule: always use git stash push -u when stashing with untracked files.
4. Team rule: never run git add . on main — always add files individually or use git add -p.
5. Added pre-commit hook to warn when new files are staged on main that do not exist on the previous commit.- git stash does not include untracked files by default. Use git stash -u to include them.
- Untracked files follow you across branch switches. They are not part of the stash or the commit — they are just files in the working directory.
- Never run git add . on main. Stage files individually or use git add -p to review each hunk.
- Always label stashes with git stash push -m 'description'. Unnamed stashes become mystery boxes.
git reflog — find the stash application entry.
3. The stash commit object still exists: git fsck --no-reflogs | grep dangling — find dangling commit objects.
4. Recover: git stash apply <hash> using a hash that looks like your stash.
5. Prevention: use git stash apply when conflicts are possible. Then git stash drop manually after resolving.git reset --hard HEAD to restore the branch to its pre-pop state.
3. Switch to the correct branch: git checkout <correct-branch>.
4. Apply there: git stash apply stash@{0} (the stash is still in the stack if you used apply, or recover via reflog if you used pop).git stash list — read the messages (this is why you always use -m).
2. If messages are unhelpful: git stash show -p stash@{0} — full diff of each stash.
3. Search stashes for a specific change: git stash show -p stash@{N} | grep 'search-term' for each N.
4. Or: git log --all --oneline --grep='search-term' — stash entries appear in the log.git log --oneline -3 — find the commit that includes the wrong files.
3. Revert: git revert <commit-hash> to undo the commit on the wrong branch.
4. Switch to correct branch: git checkout <correct-branch>.
5. Stash correctly: git stash push -u -m 'WIP: new files' to include untracked files.git fsck --no-reflogs | grep dangling — find dangling commit objects.
3. Each stash entry is a commit internally. Filter by date: look for commits created around the time you stashed.
4. Apply: git stash apply <hash> for each recovered stash commit.
5. Prevention: never run git stash clear without checking git stash list first.Key takeaways
Interview Questions on This Topic
Frequently Asked Questions
That's Git. Mark it forged?
3 min read · try the examples if you haven't