datarekha

Stashing work in progress

How to shelve half-done changes with git stash so you can switch branches instantly, then pick up exactly where you left off.

6 min read Intermediate Git Lesson 11 of 15

What you'll learn

  • How git stash saves your working directory and index to a temporary stack — without creating a commit
  • The difference between git stash pop and git stash apply, and when to choose each
  • Why plain git stash silently ignores untracked files: use -u to include them

Before you start

The last lesson named the trap: merge, rebase, and switching branches all demand a clean working tree — yet real work is rarely clean when the interruption arrives. This lesson is the escape hatch. The shelf has a name, the stash, and once you know it, “I can’t switch, I have uncommitted changes” stops being a wall.

Why not just commit?

A half-done feature commit pollutes your history with a message like “WIP do not merge.” When you eventually push, that noise is permanent. A stash, by contrast, is local-only — it never leaves your machine unless you explicitly export it — and it carries no commit SHA in your branch history. Think of it as a personal sticky note on your desk, not a page in the permanent record.

The stash as a stack

Git stores stashes in a LIFO stack (last in, first out). Every time you run git stash, a new entry is pushed on top. Every time you pop, the top entry is removed. The entries are numbered stash@{0} (top), stash@{1}, stash@{2}, and so on. The number always reflects position in the stack at that moment — if you drop stash@{1}, what was stash@{2} becomes stash@{1}.

The typical flow

Here is the complete stash-switch-fix-return cycle you will use most often.

# You are on feature/payments, mid-change
git stash          # shelf everything, restore a clean working dir

git switch hotfix/null-check   # switch freely — working dir is clean
# ... make the urgent fix, commit it ...

git switch feature/payments    # back to your branch
git stash pop      # restore your stashed work and remove it from the stack

After git stash, your working directory looks exactly as it did after your last commit. After git stash pop, it looks exactly as it did before you stashed.

The flow below shows the stash stack during this sequence.

Working dir(half-done changes)git stashstash@0stash@1 …LIFO stackgit stash popWorking dir(restored)
git stash pushes changes onto the LIFO stack; git stash pop pulls them back off and restores the working directory.

Core commands

Stash and inspect

git stash                  # stash tracked, modified files (index + working tree)
git stash list             # view the whole stack
stash@{0}: WIP on feature/payments: 3f1a8c2 Add cart total
stash@{1}: WIP on feature/payments: 3f1a8c2 Add cart total

Each entry shows the branch it came from and the commit it was made against. Without names they can blur together fast — see Named stashes below.

Restore: pop vs apply

git stash pop              # apply stash@{0}, then DROP it from the stack
git stash apply            # apply stash@{0}, but KEEP it on the stack

Use pop when you are done with the stash and want the stack clean. Use apply when you want to replay the same changes on multiple branches — or when you are nervous and want the stash as a backup until you confirm everything looks right.

Include untracked files

Named stashes

When the stack grows past one entry, stash@{0} tells you nothing useful. Name them:

git stash push -m "payments: wip cart subtotal logic"
git stash push -m "payments: experiment with tax rounding"
git stash list
stash@{0}: On feature/payments: payments: experiment with tax rounding
stash@{1}: On feature/payments: payments: wip cart subtotal logic

Apply or drop a specific entry by its index:

git stash apply stash@{1}     # apply without dropping
git stash drop  stash@{1}     # drop one entry
git stash clear               # drop every entry — no undo

Quick reference

CommandWhat it does
git stashShelf tracked modifications, restore clean working dir
git stash -uSame, plus untracked files
git stash push -m "msg"Stash with a descriptive name
git stash listShow the full stack
git stash popApply top entry and remove it from stack
git stash applyApply top entry, leave it on stack
git stash drop stash@{n}Remove one specific entry
git stash clearWipe the entire stack

In one breath

git stash shelves your modified tracked files onto a local LIFO stack and hands back a clean working directory — no WIP commit, no SHA in history. Switch branches, do the urgent thing, switch back, and git stash pop restores everything exactly (or git stash apply to restore but keep the entry, handy as a backup or to replay on several branches). Two traps: plain git stash silently skips untracked files — use -u to include them — and stashes are local-only, never pushed, cloned, or visible to teammates, so they vanish if you delete the repo. Name them with git stash push -m "..." the moment the stack grows past one, because stash@{0} tells you nothing.

Practice

Before the quiz, predict the outcome: you are mid-edit on feature with one modified tracked file and one brand-new untracked file scratch.py. You run a plain git stash, switch to main, fix a bug, switch back, and git stash pop. Which of the two files came back from the stash, where was the other one the whole time, and which single flag would have shelved both?

Quick check

0/3
Q1You run `git stash` and then `git stash list`. The output shows `stash@{0}`. You apply it with `git stash apply` instead of `git stash pop`. What is true afterward?
Q2You create a new file `notes.txt`, never run `git add` on it, then run `git stash`. You switch to another branch. Where is `notes.txt`?
Q3A colleague says: 'I stashed my changes at home last night — can you pull them down so I can keep working on your machine?' What should you tell them?

A question to carry forward

Stop and notice something about everything you have built across these two chapters: commits, branches, merges, rebases, stashes — every last one lives on your machine alone. Unplug your laptop from the network and not one of them would be disturbed, because none has ever left. But the entire reason version control exists is the team — the colleague who needs your feature, the CI server that builds it, the teammate whose work you have to pull in. So how does your private, local repository actually talk to a shared one sitting on a server like GitHub — sending your commits up and bringing theirs down? That handshake is built on remotes, and it opens the next chapter.

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Related lessons

Explore further

Cheat sheets
Skip to content