GitIntroduction to git stash

Introduction to git stash

git stash is Git's built-in scratchpad. It takes the changes in your working directory and staging area, tucks them away on a private stack, and gives you back a clean working tree — as if you had just checked out the current commit. Later you can pop those changes back exactly where you left off. Think of it as a "pause button" for uncommitted work.

The 60-second mental model

What stash does to your three trees

Text
Before stashing:
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   Working    │    │   Staging    │    │ Repository   │
│  (dirty)     │    │  (dirty)     │    │   (HEAD)     │
└──────────────┘    └──────────────┘    └──────────────┘

After  git stash :
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   Working    │    │   Staging    │    │ Repository   │
│  (clean)     │    │  (clean)     │    │   (HEAD)     │
└──────────────┘    └──────────────┘    └──────────────┘
                                ▲
                                │
                       ┌────────┴───────┐
                       │  Stash stack   │
                       │  stash@{0}  ◀── most recent
                       │  stash@{1}
                       │  stash@{2}     │
                       └────────────────┘
When to reach for stash
  • Urgent hotfix interrupts a feature. You are mid-feature, a P0 bug lands, and you need a clean branch right now.

  • Switching branches with dirty files. Git refuses to switch if a checkout would clobber local changes — stash, switch, come back.

  • Pulling on a dirty branch. git pull on a dirty tree often fails; stash first, pull, pop.

  • Mid-debug experiments. You added a bunch of console.log calls and want to test something else briefly without losing them.

  • Quick demo or screenshot. You want HEAD as-is for a moment without committing WIP.

When NOT to use stash
  • Long-lived WIP. If you will not pop within a day or two, make a WIP branch and commit instead. Stashes are easy to forget about.

  • Work you need to share. Stashes are local-only. They never travel through push or fetch.

  • Work that crosses machines. Same reason — stashes do not sync.

  • As a substitute for branches. Branches are cheap. Use them.

The two basic flows

Flow 1: stash and pop

Bash
# You are mid-edit on feature/login
git status
#   modified:   src/login.js
#   modified:   src/auth.js

git stash
#   Saved working directory and index state WIP on feature/login: 3f2a1b9 Wire up form

git status
#   nothing to commit, working tree clean

# ... do something else ...

git stash pop
#   On branch feature/login
#   Changes not staged for commit:
#     modified:   src/login.js
#     modified:   src/auth.js
#   Dropped refs/stash@{0} (a1b2c3d...)

Flow 2: stash, switch, and apply later

Bash
git stash push -m "WIP login form"
git switch main
git pull
git switch -
git stash pop
What gets stashed (and what doesn't)
  • Stashed by default: tracked files that are modified, and content currently in the staging area.

  • NOT stashed by default: untracked files (brand-new files Git has never seen).

  • NOT stashed by default: ignored files (anything matching .gitignore).

  • Use -u to include untracked. Use -a to include ignored as well.

The most common stash gotcha
You create a new file `notes.md`, run `git stash`, switch branches, and find `notes.md` still sitting there. That's because untracked files are not stashed by default. Either `git add` it first, or stash with `-u`.
The stash stack
Stashes are kept on a LIFO (last-in, first-out) stack. Every `git stash` pushes a new entry on top, indexed from zero. The newest stash is always `stash@0`; older ones get pushed down to `stash@1`, `stash@2`, and so on.

Stack visualisation

Text
           push                        pop
            │                            ▲
            ▼                            │
        ┌─────────────────────────────────────┐
        │  stash@{0}  ← newest, popped first  │
        │  stash@{1}                          │
        │  stash@{2}                          │
        │  stash@{3}  ← oldest                │
        └─────────────────────────────────────┘
Stashes are local-only
Warning
Stashes live in `.git/refs/stash` on your machine and are *never* transferred by `git push`, `git fetch`, or `git pull`. If you wipe your laptop, your stashes are gone. If you need that work to survive, commit it on a branch.
A complete end-to-end example

Urgent hotfix while mid-feature

Bash
# 1. Mid-feature, dirty tree
git status
#   modified: src/checkout.js

# 2. P0 bug lands. Stash with a message.
git stash push -m "WIP checkout total calculation"

# 3. Hop to main, branch off, fix, commit, push, PR.
git switch main
git pull
git switch -c hotfix/login-crash
# ...edit...
git commit -am "Fix null user in login flow"
git push -u origin hotfix/login-crash

# 4. Back to the feature
git switch feature/checkout
git stash pop
# Picks up exactly where you left off
Useful commands at a glance

The stash subcommand family

Bash
git stash                  # stash tracked changes (shortcut for: git stash push)
git stash push -m "msg"    # stash with a message
git stash list             # show the stack
git stash show             # summary of stash@{0}
git stash show -p          # full diff of stash@{0}
git stash apply            # restore stash@{0}, keep it on the stack
git stash pop              # restore stash@{0}, then drop it
git stash drop             # delete stash@{0}
git stash clear            # delete ALL stashes (irreversible-ish)
git stash branch <name>    # create a branch from stash@{0}
Tip
Always give stashes a message with `-m`. A stack of unnamed `WIP on main: ...` entries is impossible to tell apart a week later. Treat stash messages like very short commit messages — future you will thank you.
Stash is a tool, not a workflow
Stash is great in 30-second-to-30-minute windows. If you find yourself with five stashes that are days old, that's a smell: promote each to a real branch with `git stash branch`.