Homeβ€Ί DevOpsβ€Ί Git Stash: Save and Restore Work in Progress

Git Stash: Save and Restore Work in Progress

Where developers are forged. Β· Structured learning Β· Free forever.
πŸ“ Part of: Git β†’ Topic 15 of 19
Master git stash to shelve uncommitted changes, switch context instantly, and restore work safely.
πŸ§‘β€πŸ’» Beginner-friendly β€” no prior DevOps experience needed
In this tutorial, you'll learn:
  • git stash push -m 'description' β€” always add a message. Unnamed stashes become mystery boxes within 24 hours.
  • Use git stash -u to include untracked files; without it, new files stay in your working directory when you switch branches.
  • Prefer git stash apply over pop when conflicts are possible β€” pop deletes the stash before you resolve conflicts, leaving you with no backup.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
⚑ Quick Answer
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.

Stash is one of those Git features that feels like magic the first time you use it and becomes invisible muscle memory after a month. The command is simple; the failure modes are what trip people up.

I've seen developers lose hours of work to three specific stash mistakes: popping a stash onto the wrong branch, stashing without saving untracked files and losing them on a git clean, and accumulating a 15-entry stash stack with zero idea what's in any of them. This guide covers the command, the options that matter, and the mental model that prevents all three.

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.

git_stash_basics.sh Β· BASH
12345678910111213141516171819202122232425262728
# Save current work to stash (tracked files only)
git stash

# Save with a descriptive message β€” always do this
git stash push -m "WIP: payment retry exponential backoff"

# Include untracked files (new files not yet git add'd)
git stash push -u -m "WIP: new PaymentRetryService class"

# Restore most recent stash AND remove it from the stack
git stash pop

# Restore most recent stash but KEEP it in the stack
git stash apply

# List all stashes
git stash list
# Output:
# stash@{0}: On feature/payment-retry: WIP: payment retry exponential backoff
# stash@{1}: On main: WIP: hotfix debug logging

# Restore a specific stash by index
git stash pop stash@{1}
git stash apply stash@{1}

# See what's in a stash before applying
git stash show stash@{0}
git stash show -p stash@{0}   # Full diff
β–Ά Output
Saved working directory and index state On feature/payment-retry: WIP: payment retry exponential backoff

# git stash list:
stash@{0}: On feature/payment-retry: WIP: payment retry exponential backoff
stash@{1}: On main: WIP: hotfix debug logging

# git stash show stash@{0}:
src/main/java/io/thecodeforge/payment/PaymentRetryService.java | 47 +++++++++
1 file changed, 47 insertions(+)

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.

git_stash_pop_vs_apply.sh Β· BASH
12345678910111213141516171819202122
# Scenario: you might have conflicts β€” use apply, not pop
git stash apply stash@{0}

# If it applied cleanly with no conflicts, manually drop the stash
git stash drop stash@{0}

# If there ARE conflicts, resolve them, then drop manually
# The stash is still in the stack β€” you haven't lost anything
git status                # Shows conflicted files
# ... resolve conflicts ...
git add .
git stash drop stash@{0}  # Now safe to remove

# Apply same stash to two branches
git checkout feature/branch-a
git stash apply stash@{0}    # Applied to branch A β€” stash still exists
git checkout feature/branch-b
git stash apply stash@{0}    # Applied to branch B too
git stash drop stash@{0}     # Now clean up

# Clear ALL stashes (nuclear β€” use with care)
git stash clear
β–Ά Output
# Conflict during apply:
Auto-merging src/main/java/io/thecodeforge/payment/PaymentService.java
CONFLICT (content): Merge conflict in src/main/java/io/thecodeforge/payment/PaymentService.java

# Stash is still in stack β€” safe to resolve then drop
⚠️
git stash pop deletes the stash even on conflictIf you run git stash pop and hit a merge conflict, Git removes the stash entry before you resolve the conflict. Your stash is gone from the stack. If you then abort the merge or mess up the conflict resolution, you have no backup. For anything involving cross-branch work or files you've touched recently on main, always use git stash apply so the stash survives a bad merge.

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_partial.sh Β· BASH
123456789101112131415
# Stash only specific files
git stash push -m "WIP: retry config" -- src/main/java/io/thecodeforge/payment/RetryConfig.java

# Stash multiple specific files
git stash push -m "WIP: two related files" \
  -- src/main/java/io/thecodeforge/payment/RetryConfig.java \
  -- src/main/java/io/thecodeforge/payment/RetryPolicy.java

# Interactive patch mode β€” choose which hunks to stash
git stash push -p -m "WIP: partial changes"
# Git shows each change hunk and asks: stash this hunk? [y/n/q/a/d/?]

# Create a branch from a stash (useful for long-lived stashes)
git stash branch feature/retry-config stash@{0}
# Creates new branch at the commit where you stashed, applies the stash, drops it
β–Ά Output
Saved working directory and index state On feature/payment-retry: WIP: retry config

# Only RetryConfig.java was stashed
# RetryPolicy.java remains in working directory
CommandEffectStash Removed?Best For
git stashStash tracked filesN/AQuick context switch
git stash -uStash tracked + untrackedN/AWhen you have new files
git stash popApply + remove from stackYesNormal restore β€” 95% of cases
git stash applyApply, keep in stackNoRisky merges or multi-branch apply
git stash dropRemove without applyingYesDiscard stash you no longer need
git stash clearRemove ALL stashesYes (all)Spring cleaning β€” careful
git stash branch <name>Create branch from stashYesLong-lived stashes that deserve a branch

🎯 Key Takeaways

  • git stash push -m 'description' β€” always add a message. Unnamed stashes become mystery boxes within 24 hours.
  • Use git stash -u to include untracked files; without it, new files stay in your working directory when you switch branches.
  • Prefer git stash apply over pop when conflicts are possible β€” pop deletes the stash before you resolve conflicts, leaving you with no backup.
  • git stash branch <name> <stash> converts an old stash into a proper branch β€” the right move when a stash has grown into more work than you expected.
  • Stashes are global to the repo, not scoped to a branch β€” applying a stash on the wrong branch is an easy mistake with sometimes messy consequences.

⚠ Common Mistakes to Avoid

  • βœ•Running git stash without -u and losing new (untracked) files β€” they stay in the working directory when you switch branches and get committed to the wrong place.
  • βœ•Accumulating a deep stash stack with no messages β€” stash@{7} with no description is useless. Always use git stash push -m 'description'.
  • βœ•Using git stash pop when conflicts are possible β€” pop deletes the stash before the conflict is resolved. Use apply + manual drop instead.
  • βœ•Forgetting that git stash is per-repository, not per-branch β€” stashes don't belong to branches. You can pop a stash made on feature/x onto main, which is sometimes intentional and sometimes a very bad day.
  • βœ•Running git stash clear thinking it only clears 'old' stashes β€” it removes everything with no confirmation and no recovery except reflog.

Interview Questions on This Topic

  • QWhen would you use git stash apply instead of git stash pop?
  • QA developer stashed changes, switched branches, and now can't find which stash contains their work. How do they find and apply the right one?
  • QExplain how git stash stores its data internally. Is a stash a commit?
  • QYou have three stashes and want to apply the second one without disturbing the others. What command do you run?

Frequently Asked Questions

What is the difference between git stash pop and git stash apply?

git stash pop applies the stash and immediately removes it from the stash stack. git stash apply applies it but leaves it in the stack. Use apply when there's a chance of merge conflicts (so the stash survives if the apply fails) or when you want to apply the same stash to multiple branches.

Does git stash save untracked files?

No, by default git stash only saves tracked files that have been modified. To include untracked files (new files not yet added with git add), use git stash push -u or git stash push --include-untracked.

How do I see what's in a stash before applying it?

Run git stash show stash@{N} for a summary of changed files, or git stash show -p stash@{N} for the full diff. Replace N with the stash index from git stash list.

Can I recover a stash I accidentally dropped?

Sometimes. Run git fsck --no-reflogs | grep commit to find dangling commit objects (stash entries are commits internally). You can then run git stash apply <hash> on any hash that looks like your lost stash. This works within the gc.reflogExpire window (default 30 days) as long as you haven't run git gc.

πŸ”₯
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousGit Squash Commits: Combine Multiple Commits into OneNext β†’Git Cherry Pick: Apply Commits Across Branches
Forged with πŸ”₯ at TheCodeForge.io β€” Where Developers Are Forged