Skip to content
Codeloom
Git

Advanced Git Stash Techniques

Go beyond basic git stash. Learn partial stashing, stash branches, managing multiple stashes, and recovering dropped stashes.

·7 min read · By Codeloom
Intermediate 10 min read

What you'll learn

  • Stashing specific files and hunks
  • Managing multiple named stashes
  • Creating branches from stashes
  • Recovering dropped and cleared stashes
  • Stash workflows for real-world scenarios

Prerequisites

  • Basic git stash usage (stash, pop)
  • Familiarity with Git staging area
  • Basic command line skills

Most developers know git stash and git stash pop. But stash has many more capabilities: you can stash specific files, stash individual hunks, name your stashes, create branches from them, and even recover stashes you accidentally dropped.

Beyond basic stash

Quick refresher on the basics:

# Stash all tracked modified files
git stash

# Restore the most recent stash
git stash pop

# List all stashes
git stash list

Now let’s go deeper.

Naming stashes

By default, stashes get auto-generated descriptions that are hard to identify:

git stash list
# stash@{0}: WIP on feature: abc1234 Add login form
# stash@{1}: WIP on main: def5678 Update readme

Give your stashes meaningful names:

git stash push -m "half-finished login validation"
git stash push -m "experimental caching approach"

Now the list is useful:

git stash list
# stash@{0}: On feature: experimental caching approach
# stash@{1}: On feature: half-finished login validation

Stashing specific files

Stash only certain files, leaving others in the working directory:

# Stash specific files
git stash push -m "database changes" src/db/connection.js src/db/schema.sql

# Stash everything in a directory
git stash push -m "frontend changes" src/components/

This is useful when you have changes to multiple systems and only want to set aside some of them.

Stashing untracked and ignored files

By default, git stash only stashes tracked files:

# Include untracked files
git stash push --include-untracked
# Or the short form
git stash push -u

# Include untracked AND ignored files (everything)
git stash push --all
# Or short form
git stash push -a

This is essential when you have new files that are not yet tracked and you want to stash them too.

Partial stashing (interactive)

Stash individual hunks within a file, keeping the rest in your working directory:

git stash push -p

Git shows each hunk and asks what to do:

diff --git a/src/user.js b/src/user.js
@@ -10,6 +10,10 @@ class User {
+  validate() {
+    if (!this.email) throw new Error('Email required');
+  }

Stash this hunk [y,n,q,a,d,s,e,?]?

Options:

  • y: Stash this hunk
  • n: Do not stash this hunk
  • s: Split this hunk into smaller hunks
  • q: Quit (do not stash remaining hunks)

This lets you stash the validation logic while keeping the rest of your changes.

Applying vs popping

The difference:

  • git stash pop applies the stash and removes it from the stash list.
  • git stash apply applies the stash but keeps it in the stash list.
# Apply and remove
git stash pop

# Apply and keep (useful if you want to apply the same stash to multiple branches)
git stash apply

# Apply a specific stash
git stash apply stash@{2}
git stash pop stash@{1}

Use apply when you might want to use the stash again. Use pop when you are done with it.

Viewing stash contents

# Show the diff of the most recent stash
git stash show

# Show the full diff (including file contents)
git stash show -p

# Show a specific stash
git stash show -p stash@{2}

# Show which files are in a stash
git stash show --name-only stash@{1}

# Show stat summary
git stash show --stat stash@{0}

Creating a branch from a stash

If your stashed changes conflict with the current branch, or if you decide the stash deserves its own branch:

# Create a new branch from a stash
git stash branch new-feature-branch stash@{0}

This:

  1. Creates a new branch from the commit where the stash was originally created.
  2. Applies the stash.
  3. Drops the stash if the apply succeeds.

This is guaranteed to apply cleanly because it goes back to the exact state where the stash was created.

Dropping and clearing stashes

# Drop a specific stash
git stash drop stash@{2}

# Drop the most recent stash
git stash drop

# Clear ALL stashes (careful!)
git stash clear

Recovering dropped stashes

If you accidentally dropped or cleared a stash, you can often recover it. Stashes are commit objects, and Git does not immediately garbage-collect them.

# Find dangling commits (potential stashes)
git fsck --no-reflogs | grep "dangling commit"

# Output:
# dangling commit abc1234def567890
# dangling commit fed0987654321cba

# Inspect each one to find your stash
git show abc1234def567890

# If that's your stash, re-apply it
git stash apply abc1234def567890

# Or create a branch from it
git checkout -b recovered-stash abc1234def567890

A more targeted approach using the reflog:

# Search the reflog for stash entries
git log --graph --oneline --all $(git fsck --no-reflogs 2>/dev/null | grep "dangling commit" | cut -d' ' -f3)

This only works before Git garbage collects (usually 30 days for unreachable objects). Run it soon after the accidental drop.

Stash with keep-index

Stash only the unstaged changes, keeping the staged changes in the index:

git stash push --keep-index

This is useful for testing your staged changes in isolation:

# Stage the changes you want to commit
git add src/feature.js

# Stash everything else
git stash push --keep-index -m "test staged only"

# Run tests on just the staged changes
npm test

# Restore the rest
git stash pop

Managing many stashes

If you find yourself with many stashes, here are some tips:

Always name your stashes

git stash push -m "WIP: user profile redesign"
git stash push -m "debug: extra logging for payment flow"

Search stashes by message

git stash list | grep "payment"
# stash@{3}: On main: debug: extra logging for payment flow

Script to show all stashes with their diffs

#!/bin/bash
# show-stashes.sh
for stash in $(git stash list --format="%gd"); do
    echo "=== $stash ==="
    git stash show --stat "$stash"
    echo ""
done

Real-world scenarios

Scenario: wrong branch

You made changes on main but meant to be on a feature branch:

# Stash the changes
git stash push -m "changes for feature branch"

# Switch to the right branch
git checkout feature/user-auth

# Apply the stash
git stash pop

Scenario: pulling with local changes

You have local changes and need to pull remote updates:

git stash push -m "local changes before pull"
git pull --rebase
git stash pop
# Resolve any conflicts

Scenario: testing a clean build

You want to verify the project builds from a clean state:

git stash push -u -m "stash everything for clean build test"
npm run build
npm test
git stash pop

Scenario: cherry-picking changes between branches

# On feature-a, stash specific files
git stash push -m "shared utility" src/utils/shared.js

# Switch to feature-b
git checkout feature-b

# Apply the stash
git stash pop

Summary

Git stash is more than stash and pop. Name your stashes with -m for clarity. Stash specific files with git stash push <files>. Use -p to stash individual hunks. Use --keep-index to test staged changes in isolation. Create branches from stashes when they grow into real work. Recover dropped stashes with git fsck --no-reflogs before garbage collection runs. The key habit: always name your stashes, because unnamed stashes become mysteries within a day.