Stash Work and Recover It
Learn how to stash work in progress and recover it with hands-on steps in this Git tutorial.
Focus: stash work in progress and recover it
You're mid-refactor on a feature branch, and the code is a mess — half-edited files, a broken test, and a teammate just asked you to urgently fix a bug on main. You cannot commit this broken work, but you also can't lose it. Do you copy files to a temp folder? Email yourself a patch? There's a better way. Git's stash lets you set aside work in progress in seconds, clean your working directory, and recover it whenever you're ready — without a single commit. In this lesson, you'll learn how to stash work in progress and recover it safely, avoid the common pitfalls, and integrate this tool into your daily Git workflow.
The problem this lesson solves
Every developer hits the same wall: you're deep in a feature, you've modified five files, and suddenly you need to switch branches — but your working directory is dirty. If you git checkout to another branch, Git may refuse because it would overwrite your uncommitted changes, or worse, it might let you switch and carry the changes into the wrong branch.
The core pain: You can't commit work that isn't finished and tested, but you can't just throw it away. Copying files manually is error-prone and slow. Stash solves this by giving you a safe, fast way to shelf your changes and restore them exactly as they were.
This is not a rare scenario. It happens during hotfixes, when you need to pull the latest changes, when you want to test a clean state, or when you switch between tasks. Stash work in progress and recover it is a core Git skill that separates beginners from confident practitioners.
By the end of this lesson, you'll be able to:
- Explain why stashing beats committing or copying files in these situations.
- Safely stash, list, apply, and pop changes.
- Recover accidentally popped stashes.
- Choose between stash and other Git features like commits or worktrees.
Core concept / mental model
Think of Git stash as a safety drawer for your changes. When you stash, Git takes your modified tracked files (and optionally staged and untracked files) and stores them in a stack-like structure called the stash. It then resets your working directory to the last commit — clean and tidy. Later, you can pull the changes out of the drawer and put them back onto your working directory.
Key ideas to internalize:
- Stash is not a commit. It lives in a separate area (
.git/refs/stash) and doesn't become part of your branch history. - Stash is stack-based. Each stash push adds a new entry on top. You apply or pop from the top by default.
- Stash preserves your changes with metadata. Each stash entry records the commit it was based on, so you can reason about which changes belong to which state.
- Stash can include untracked files if you ask it to (with
-u), but by default it only stashes tracked changes. - Recovering is two-way:
applyleaves the stash in the stack;popapplies and removes it. If you lose a stash, there are ways to recover it (ref logs!)
Here's a visual in words:
Before stash: Working dir = messy (5 changed files)
|
v
git stash push
|
v
Working dir = clean (like last commit) + stash stack has entry #0
|
v
git stash pop
|
v
Working dir = messy again (5 changed files) + stash entry #0 gone (if pop)
How it works step by step
Let's walk through the typical workflow logically, from start to finish. Visualize each step as a cause-and-effect relationship.
Step 1: Check your dirty state
Before you stash, check what's changed:
git status
This shows modified tracked files, staged files, and untracked files. You need to know what will and won't be included in the stash.
Step 2: Stash your changes
Run the basic stash command:
git stash push -m "WIP: refactor auth"
A short message helps you identify the stash later. If you don't provide a message, Git uses the latest commit message. By default, only tracked and staged changes are stashed. Untracked files are ignored.
Step 3: Verify the stash and clean state
git stash list
git status
git stash list shows entries like stash@{0}: On branch: WIP: refactor auth. Your working directory is now clean (except for untracked files).
Step 4: Switch branches or do your urgent work
Now you can safely switch branches, pull, make the hotfix, commit it, and switch back.
Step 5: Recover your stashed work
When you're ready to pick up where you left off, you have two options:
git stash pop— applies the stash and removes it from the stack.git stash apply— applies the stash but keeps it in the stack (useful if you want to apply it to multiple branches).
Both default to the most recent stash (stash@{0}). You can specify any stash using its ID.
Step 6: Resolve conflicts (if any)
When you pop or apply onto a branch that has diverged, Git may hit conflicts. You'll need to resolve them just like a merge conflict, then git add the resolved files. The stash remains in the stack until you clear it — so after resolving, it's wise to pop again to drop it if you're done.
Hands-on walkthrough
Let's put this into practice with a concrete example. We'll create a repo, make changes, stash them, switch branches, fix something, then recover and continue.
Set up the playground
mkdir stash-demo && cd stash-demo
git init
git config user.email "demo@example.com"
git config user.name "Demo"
echo "Hello" > app.py
git add app.py
git commit -m "Initial commit"
# Now modify the file (uncommitted)
echo "Hello, world!" >> app.py
Now we have a working directory with one modified file. Let's verify:
git status
Expected output:
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: app.py
Stash the change
git stash push -m "WIP: add greeting"
Now check the state:
git stash list
git status
Expected output:
stash@{0}: On master: WIP: add greeting
On branch master
nothing to commit, working tree clean
Do urgent work on another branch
git checkout -b hotfix
# fix a typo in app.py? No, let's create a new file
echo "Fix" > fix.txt
git add fix.txt
git commit -m "Hotfix"
git checkout master
Recover the stash
Now come back to master and pop:
git stash pop
Expected output (similar):
On branch master
Changes not staged for commit:
modified: app.py
no changes to commit
Dropped refs/stash@{0} (abcdef1234567890123456789012345678901234)
Your change is back, and the stash entry is gone. Verify with git stash list — it should be empty.
Pro tip: If you want to apply the same changes to multiple branches, use
git stash applyinstead ofpop, then pop only when you're finally done. This is handy when you're carrying a WIP across feature branches.
More advanced: including untracked files
By default, untracked files are left alone. To include them in the stash:
echo "new feature" > new_feature.py
git stash push -u -m "WIP with untracked"
Now the untracked file is stashed too. git stash pop restores it.
Compare options / when to choose what
You're not forced to stash — Git offers other ways to handle WIP. Here's a comparison to help you choose.
| Approach | When to use | Pros | Cons |
|---|---|---|---|
git stash |
Quick switch, temporary shelf | Instant, reversible, no commit pollution | Not ideal for long-lived WIP; only one default stack |
| Create a WIP commit (possibly on a branch) | Work that will live for days/weeks | Keeps history, can share with others | Pollutes history; you must reset later |
git worktree |
You need to work on two branches simultaneously | Clean isolation, no stash needed | Heavier setup; separate directories |
| Copy files manually | Extremely small changes | Simple, no Git knowledge | Error-prone, loses merge context |
Decision guide: - Temporary (minutes to a few hours): stash is your friend. - Ongoing feature (days): create a dedicated branch and commit incrementally (even if messy) — it's easier to manage. - Need to switch contexts repeatedly: worktrees shine, as you don't have to stash at all. - Never copy files manually if you can avoid it.
Variations to consider:
- git stash branch <branch> <stash>: creates a new branch from the stash's original commit and applies the stash there. Great when you realise you were on the wrong branch.
- git stash show -p stash@{0}: preview the changes in a stash without applying it.
- Use git stash push -- <file> to stash only specific files.
Troubleshooting & edge cases
You'll hit a few snags when stashing. Here's how to diagnose and fix the most common ones.
Problem 1: git stash pop results in conflicts
Symptom: conflicts appear in files; Git reports merge conflict markers (<<<<<<<).
Cause: The working branch has changed since you stashed — e.g., you committed other changes to the same lines.
Fix: Resolve each conflicting file like a merge. Then git add the resolved files. The stash still exists because the pop failed; fix, add, then git stash drop to remove it.
Problem 2: You popped a stash by accident and now it's gone
Symptom: git stash list is empty, but your changes are as expected in the working directory — you actually wanted to apply without dropping.
Cause: You used pop when you meant to use apply.
Fix: The stash is not lost forever! You can recover it using the reflog:
git fsck --unreachable | grep commit
git reflog show --all | grep stash
Then use the commit hash to create a new stash:
git stash apply <hash>
Pro tip: Don't panic. Git's reflog keeps a record of everything for 30 days by default. You can almost always recover a popped stash.
Problem 3: Untracked files missing after stash
Symptom: After popping, one of your new files is missing.
Cause: You stashed without -u, so untracked files were never included. They remained in the working directory (not stashed) — but if you then switched branches, the file might have stayed or been overwritten.
Fix: Always use -u if you have untracked files you want to shelf. Check where your file went with git status. If it's gone, check the stash's git stash show -p to see if it's inside a stash entry.
Problem 4: You stashed more than you meant to
Symptom: You stashed staged and unstaged changes, but you only meant to stash unstaged changes.
Cause: git stash push stashes both by default.
Fix: Use -- <pathspec> to limit what you stash. Or, if you want to keep staged changes, use git stash push --keep-index to stash only unstaged changes.
Problem 5: git stash pop says "Could not restore untracked files"
Symptom: The stash includes untracked files, but there's a file with the same name in the working directory.
Cause: A conflict between the stashed untracked file and a new file.
Fix: Either delete or rename the conflicting file in your working directory, then pop again.
What you learned & what's next
You now have the git stash superpower. Let's recap what you achieved in this lesson:
- You can stash work in progress with
git stash pushand a descriptive message. - You can list your stash stack with
git stash listand inspect a stash's contents. - You can recover it with
git stash pop(apply and drop) orgit stash apply(keep it). - You know how to handle untracked files with
-uand how to stash only specific files. - You can troubleshoot conflicts, accidental pops, and missing files using Git's safety nets like
reflog. - You know when to choose stash over commits or worktrees.
That covers every learning objective from the brief: you can explain the core idea behind stashing and you've completed a practical exercise.
What's next? In the next lesson, you'll look at cleaning your working tree with git clean — the perfect companion to stash for keeping your repo tidy. You'll learn how to remove untracked files and directories safely, and how to combine git clean with stash to prepare a pristine state for the next merge or branch switch.
Keep practicing stash until it feels natural — your future self will thank you every time you have to drop everything and fix an emergency.
Practice recap
Create a new repo, add a file, then edit it. Practice git stash push -m "test", check git stash list, then git stash pop. Repeat with an untracked file using -u. For a bonus, try git stash apply twice to see how to reuse the same stash.
Common mistakes
- Using
git stash popwhen you meant to keep the stash for later—preferapplyif you need to reuse the change across branches. - Forgetting
-uwhen you have untracked files, leading to those files not being stashed (and possibly lost if you switch branches). - Assuming stash is a substitute for commits—if WIP will last for days, a branch + commit is cleaner and easier to track.
- Accidentally popping the wrong stash by not specifying an index (e.g.,
git stash pop stash@{1}).
Variations
- Use
git stash push -- <file>to stash only selected files instead of everything. - Use
git stash branch <branch> <stash>to recover a stash and create a branch at the right commit in one step. - Consider
git worktreeinstead of stash when you need to work on two branches simultaneously without ever dirtying your main working directory.
Real-world use cases
- A developer must drop a mid-refactor to patch a production bug; stash shelves the WIP in seconds, allowing a clean branch switch and hotfix commit.
- A team uses
git stash push -uto temporarily move untracked config files aside when switching between feature branches with different environments. - A developer accidentally pops a stash and loses it, then recovers it via
git reflogbefore reapplying—saving hours of rework.
Key takeaways
git stashsafely shelves uncommitted changes (tracked + staged by default) and gives you a clean working directory.git stash popapplies the top stash and removes it;git stash applyapplies without dropping—use each intentionally.- Including untracked files requires
-u; otherwise they stay behind and could be overlooked. - You can stash specific files with
git stash push -- <paths>—great for partial WIP. - Lost stashes are recoverable via the reflog and
git fsck, so don't panic when you accidentally pop. - Resolve pop conflicts like merge conflicts, then drop the stash only after you've verified the result.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.