Build the mental model
An urgent bug report comes in and you need to switch branches right now, while your feature branch has half-finished, uncommitted changes. Git normally refuses to switch if it would overwrite them.
`git stash` takes every change in your working directory and staging area, tucks it into a separate storage area, and resets your working directory back to the last commit.
- The stash isn't tied to any branch — it's stored independently, like a stack
- `git stash pop` reapplies the most recent stash and removes it from the stack
- `git stash apply` reapplies it while keeping a copy on the stack
You can stash multiple times before popping anything — each stash adds to the stack, and `git stash list` shows what's waiting.
STASH: PAUSE, SWITCH, RESUME
----------------------------
STASH: PAUSE, SWITCH, RESUME
------------------------------
working changes (uncommitted)
|
git stash
v
[ stash stack ] <- changes stored, working dir now clean
|
(switch branches, do other work)
|
git stash pop
v
working changes restored, exactly as beforeConnect it to a real scenario
Stash
With uncommitted changes present, run `git stash` — Git reports success and `git status` confirms the tree is clean.
Switch branches
Check out wherever you need freely, then come back to your original branch.
Pop it back
`git stash pop` reapplies the changes to your working directory exactly as they were.
Pop can conflict
If the branch changed underneath it, stash pop can conflict just like a merge. The stash stays on the stack until resolved, so nothing is lost.
Try the working example
git init -q -b main
git config user.name "Thuta Learner"
git config user.email "learner@example.com"
export GIT_AUTHOR_NAME="Thuta Learner"
export GIT_AUTHOR_EMAIL="learner@example.com"
export GIT_COMMITTER_NAME="Thuta Learner"
export GIT_COMMITTER_EMAIL="learner@example.com"
echo "console.log('feature in progress');" > app.js
git add app.js
GIT_AUTHOR_DATE="2026-01-06T09:00:00" GIT_COMMITTER_DATE="2026-01-06T09:00:00" \
git commit -m "Initial commit"
git branch -M main
git branch hotfix
echo "console.log('half-written feature');" >> app.js
git status
git stash
git status
git checkout hotfix
git checkout main
git stash pop
git status
cat app.js$ git status
On branch main
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.js
no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on main: b47b383 Initial commit
$ git status
On branch main
nothing to commit, working tree clean
$ git checkout hotfix
Switched to branch 'hotfix'
$ git checkout main
Switched to branch 'main'
$ git stash pop
On branch main
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.js
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (e9ef4229ba0e959bd1d31c7dddbe7bde3b1dd675)
$ git status
On branch main
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.js
no changes added to commit (use "git add" and/or "git commit -a")
$ cat app.js
console.log('feature in progress');
console.log('half-written feature');5-minute try-it
Modify a tracked file without committing, then run `git stash` and confirm with `git status` that your tree is clean. Switch to another branch and back. Run `git stash list` before popping to see the stash waiting on the stack, then `git stash pop` and confirm your changes are back with `git diff`.
One important caution
`git stash` shelves both staged and unstaged changes together by default — if you only wanted to stash part of your work, you need `git stash push -- <file>` or `git stash -p` instead of a plain stash.
Popping a stash can produce merge conflicts if the branch changed underneath it — the stash isn't dropped from the stack until the conflict is resolved and you run `git stash drop` (or pop succeeds cleanly).
Git Documentation: git-stash — Git & GitHub