Git Stash: How to Save Unfinished Work Without Committing
Practice4 minInnovialabs editorial team
In short
git stash temporarily moves uncommitted changes onto a separate stack and resets your working copy to the last commit; bring them back with git stash pop or apply, and use a WIP branch for work that will wait for days.
What git stash does
git stash takes your uncommitted changes (in the working copy and the index), saves them on a special stack and returns your files to the state of the last commit. The classic case: you are halfway through a task and suddenly need to switch branches to fix a bug.
git stash push -m "payment form, validation half done"
git switch hotfix/login
# ...fix, commit...
git switch feature/payment
git stash pop
Plain git stash is the same as git stash push without a message.
The core commands
| Command | What it does |
|---|---|
git stash push -m "text" | Stash changes with a clear name |
git stash list | Show all entries: stash@{0}, stash@{1}… |
git stash show -p stash@{1} | Show the diff of a specific entry |
git stash pop | Apply the latest entry and remove it from the stack |
git stash apply stash@{1} | Apply an entry but keep it on the stack |
git stash drop stash@{1} | Delete one entry |
git stash clear | Delete all entries at once |
pop or apply? pop is the everyday choice. apply helps when you want the same changes in several branches or are not sure the apply will go smoothly.
Indexes shift: the newest entry is always stash@{0}. So check git stash list before running drop or apply with a number.
Untracked files and specific paths
By default stash only takes tracked files. New files Git has never seen stay in the working copy.
git stash push -u(or--include-untracked) also stashes untracked files.git stash push -a(--all) also stashes ignored files. Be careful: things likenode_modulesor build output end up there too.git stash push -- src/api.ts src/utils/stashes only the listed paths.git stash push -plets you pick individual hunks interactively.git stash push --keep-indexstashes everything except what is already staged. Handy for checking that what you are about to commit actually works on its own.
Naming your stashes
Without -m, an entry looks like WIP on main: 3f2a1c4 last commit message. A week later you have several of them and no idea which is which. The rule is simple: always add a message — short and specific, saying what the task is and how far along it is.
Conflicts when restoring
If someone changed the same lines while your changes sat in the stash, git stash pop ends with a conflict. Important: on conflict the entry is not removed from the stack, even though you ran pop.
What to do:
- Open the files with
<<<<<<<markers and resolve them as in a normal merge. - Mark them resolved with
git add <file>(orgit restore --staged <file>if you do not want them staged). - Check that everything is in place, then remove the entry manually with
git stash drop.
If the conflict is too messy, there is a safe route: git stash branch fix-stash stash@{0}. Git creates a branch from the commit where the stash was made, applies the changes there without conflicts and drops the entry if that succeeds.
When a WIP branch is better
Stash is a tool for minutes and hours. It lives only in your local repository, is never pushed to the remote and gets lost easily among other entries.
Commit to a separate branch instead if:
- the work is paused for several days;
- you need to show the changes to a colleague or pick them up on another machine;
- you want the work backed up on the server;
- the changes are large and the history of steps matters.
git switch -c wip/payment-form
git add -A
git commit -m "WIP: payment form"
git push -u origin wip/payment-form
Later you can tidy the commits with git rebase -i or a squash merge.
Common mistakes
- Forgotten entries. Check
git stash listregularly and drop what you no longer need. - New files "disappeared". Most likely they were never stashed: without
-uthey stayed in place, or you deleted them by accident. - Running
git stash clearby mistake. Dropped entries can sometimes be recovered viagit fsck --unreachable, but do not count on it. - Popping onto the wrong branch. Changes are applied wherever you are right now. Check
git statusbefore restoring.