A typical situation: you are editing files, not ready to commit, and you suddenly need to switch to another branch to review a PR or fix a hotfix. You do not want to commit a "WIP" and you do not want to lose your work.
git stash puts the working tree into a special "pocket". You can then
switch and work elsewhere. When you come back, git stash pop restores
the changes.
Basic cycle
git stash # save the current changes
git switch hotfix # switch to where you need to go
# ... do the work ...
git switch feature # return to your branch
git stash pop # restore the changes
By default stash takes both the working tree and the index (everything
except untracked files). To include untracked files:
git stash -u # + untracked
git stash -a # + untracked + ignored (everything)
With a message
Without a message the stash gets an auto-name like "WIP on feature: abc123 last commit subject". That is hard to read. Use a description:
git stash push -m "fixed auth, logout not done yet"
Listing and inspecting
git stash list
# stash@{0}: On feature: fixed auth, logout not done yet# stash@{1}: WIP on main: 7c8a1 fix typogit stash show stash@{0} # summarygit stash show -p stash@{0} # full diffpop vs apply
git stash pop: apply and remove from the list.git stash apply: apply, keep in the list.
apply is useful when you might need the stash again. pop is for when
you know you are done with it.
Both commands take stash@{0} (the most recent) by default. You can
specify another:
git stash pop stash@{2}stash branch
If the branch has moved far ahead since the stash was made and pop
produces conflicts, you can recover the stash as a separate branch:
git stash branch fix-from-stash stash@{0}This creates a branch from the commit at which the stash was made and applies the stash in a clean environment. You can then work normally and merge.
What physically happens
A stash entry is a merge commit under refs/stash (invisible in normal
branch listings). It has at least two parents:
- first: HEAD at the time of the stash
- second: a commit with a snapshot of the index
With -u or -a a third parent is added: a commit with a snapshot of
untracked (and ignored) files. In total, one git stash creates 3-4
objects in .git/objects/. A stash can be recovered via reflog even
after stash drop, by its stash@{N} SHA.
Pitfalls
- Stash without
-udoes not hide untracked files. Untracked files are not lost; they stay in the working tree as-is. It just looks like "everything is stashed", yet aftergit switchorgit checkout .those files are visible in the new context. To actually remove untracked files, usegit stash -u. - A pop with a conflict does not delete the stash. If applying
produced a conflict, the stash stays in the list. After resolving it,
run
git stash drop stash@{0}manually. - A long-lived stash is an anti-pattern. The longer a stash sits, the
further main moves, the more painful
popbecomes. If the work matters, create a branch and commit. git stash cleardeletes everything without confirmation. If you need to clean up, prefergit stash dropone entry at a time.