← Back to Blog

Git Stash: Save Work Without Committing (Complete Guide)

You are mid-feature when a critical bug lands in your inbox. Your working directory is half-changed, you cannot commit this half-baked work, and you cannot switch branches with uncommitted changes. Git stash is exactly the tool for this - and it is far more powerful than most developers realise.

The Problem Git Stash Solves

Imagine you are building a new user authentication feature. You have modified five files, added two new ones, and none of it compiles yet. Then your manager pings you: production is down, a hotfix is needed on the main branch right now.

You have three bad options without stash:

  • Commit broken, half-finished code just to switch branches (pollutes history)
  • Copy your changes to a temp file and restore them later (error-prone)
  • Create a throw-away commit and immediately amend it later (messy)

git stash is the clean solution. It snapshots your current working directory and index, resets your working tree to a clean state, and lets you switch branches freely. When you are done with the hotfix, one command brings all your work back exactly as you left it.

Basic Stash Commands

The full stash command reference:

# Save tracked changes to the stash
git stash

# Save with a descriptive message
git stash push -m "WIP: user auth feature"

# Include untracked files (-u / --include-untracked)
git stash -u

# Include untracked AND ignored files (-a / --all)
git stash -a

# List all stashes
git stash list

# Restore latest stash AND remove it from the stash list
git stash pop

# Restore a specific stash without removing it
git stash apply stash@{2}

# Restore latest stash without removing it
git stash apply

# Delete a specific stash
git stash drop stash@{0}

# Delete ALL stashes (use with caution)
git stash clear

# Show what files are in a stash
git stash show stash@{0}

# Show the full diff of a stash
git stash show -p stash@{0}

The Stash Workflow in Practice

Here is the exact workflow for the scenario above:

# You are on feature/auth with half-finished changes
git status
# On branch feature/auth
# Changes not staged for commit:
#   modified:   src/auth.js
#   modified:   src/users.js
# Untracked files:
#   src/auth-helpers.js

# Stash everything including untracked files
git stash push -u -m "WIP: auth refactor in progress"
# Saved working directory and index state On feature/auth: WIP: auth refactor in progress

# Working tree is now clean - switch branches freely
git checkout main
git pull origin main

# Create hotfix branch and fix the bug
git checkout -b hotfix/payment-timeout
# ... make your fix ...
git commit -am "fix: increase payment gateway timeout to 30s"
git checkout main
git merge hotfix/payment-timeout
git push origin main

# Back to your feature branch
git checkout feature/auth

# Restore your stashed work
git stash pop
# On branch feature/auth
# Changes not staged for commit:
#   modified:   src/auth.js
#   modified:   src/users.js
# Untracked files:
#   src/auth-helpers.js

Your working directory is exactly as you left it. The stash is removed from the list automatically by pop. No commits were polluted, no work was lost.

pop vs apply: Which to Use

git stash pop restores the stash and deletes it from the stash list. git stash apply restores it but keeps it in the list. Use apply when you want to apply the same stash to multiple branches, or when you are unsure if the apply will produce conflicts and want to keep the stash as a backup.

# Apply the same stash changes to two branches
git checkout feature/branch-a
git stash apply stash@{0}

git checkout feature/branch-b
git stash apply stash@{0}

# Now manually drop it when done
git stash drop stash@{0}

Stashing Specific Files

By default, git stash saves all tracked modifications. Sometimes you want to stash only specific files - perhaps one file contains a debugging change you want to hide while you work on something else.

# Stash only specific files using pathspec
git stash push -m "debug logging only" -- src/debug.js src/logger.js

# Stash everything EXCEPT specific files
# First stage the files you want to keep
git add src/important.js

# Then stash everything else, keeping staged changes
git stash push --keep-index -m "stash non-staged changes"

The --keep-index flag is particularly useful: it stashes only unstaged changes and leaves your staged changes untouched. This lets you commit your ready changes cleanly while stashing the work-in-progress parts.

Stashing Untracked and Ignored Files

By default, git stash only saves tracked files (files that git knows about). New files that have never been git added are ignored. Use these flags to include them:

# -u includes new (untracked) files, but not .gitignore'd files
git stash -u

# -a includes everything: tracked, untracked, AND ignored
git stash -a
# Use -a carefully - it will stash node_modules, build artifacts,
# .env files, etc. if they are not tracked.

Always use git stash push -m "description" with a message. git stash list on a busy project with unnamed stashes like WIP on feature/auth: a3b2c1d message becomes very hard to parse after a week.

Viewing Stash Contents

Before applying a stash, it is good practice to inspect what is in it:

# List all stashes with their index and description
git stash list
# stash@{0}: On feature/auth: WIP: auth refactor in progress
# stash@{1}: On main: debug logging experiment
# stash@{2}: WIP on feature/payments: a3b2c1d add stripe integration

# Show which files are in stash@{1}
git stash show stash@{1}
# src/debug.js | 15 +++++++++++++++
# 1 file changed, 15 insertions(+)

# Show the full diff
git stash show -p stash@{1}
# diff --git a/src/debug.js b/src/debug.js
# ...full patch output...

Creating a Branch from a Stash

If your stash has been sitting for a while and applying it now conflicts with the current state of your branch, git stash branch is the cleanest solution. It creates a new branch at the commit where the stash was made and applies the stash there - before the divergence happened:

# Create a new branch from stash@{0} at the original commit
git stash branch feature/auth-recovery stash@{0}
# Switched to a new branch 'feature/auth-recovery'
# On branch feature/auth-recovery
# Changes not staged for commit:
#   modified: src/auth.js

This is especially useful when you stashed work weeks ago and the branch has moved significantly. Rather than fighting merge conflicts, you get a clean branch to work from.

Compare Changes Before Applying a Stash

Not sure what a stash contains compared to your current branch? Paste both versions into our Diff Checker to see exactly what will change before you apply.

Open Diff Checker →

Handling Stash Conflicts

If applying a stash conflicts with your current working tree, git will leave conflict markers in the affected files - just like a merge conflict:

git stash pop
# Auto-merging src/auth.js
# CONFLICT (content): Merge conflict in src/auth.js
# The stash entry is kept in case you need it again.

# Resolve conflicts in src/auth.js, then:
git add src/auth.js

# Mark the stash as fully applied by dropping it manually
git stash drop stash@{0}

Note that when a conflict occurs, git stash pop does NOT remove the stash automatically (unlike the no-conflict case). You need to git stash drop it manually after resolving.

Recovering a Dropped Stash

Accidentally ran git stash drop or git stash clear? Stash entries are stored as commit objects in git and are not immediately garbage collected. You can often recover them:

# Find dangling commits that might be lost stashes
git fsck --no-reflog | grep "dangling commit"
# dangling commit a3b2c1d4e5f6...

# Inspect a dangling commit
git show a3b2c1d4e5f6

# If it is your lost stash, apply it
git stash apply a3b2c1d4e5f6

This only works before git gc runs and cleans up unreachable objects. On most systems, git runs garbage collection automatically after a few weeks. Do not rely on this as your backup strategy - use descriptive stash messages and clean up stashes you know you no longer need.

Stash in Git GUI Tools

Every major Git GUI supports stashing with a UI:

  • VS Code: Source Control panel → three-dot menu → Stash / Pop Stash
  • GitKraken: Left panel → STASH section, drag files to stash
  • GitHub Desktop: Branch menu → Stash Changes
  • SourceTree: Repository menu → Stash
  • IntelliJ / WebStorm: Git menu → Uncommitted Changes → Stash Changes

GUI tools make it easy to see stash contents and apply them, but knowing the CLI commands is essential for terminal-based workflows and CI scripts.

Frequently Asked Questions

Does git stash save untracked files by default?

No. By default, git stash only saves tracked files that have been modified. New files that have never been git added are ignored. Use git stash -u to include untracked files, or git stash -a to include everything including gitignored files.

What is the difference between git stash pop and git stash apply?

git stash pop applies the stash and removes it from the stash list in one step. git stash apply applies it but leaves it in the list. If a conflict occurs during pop, the stash is NOT removed - you have to drop it manually after resolving. Use apply when you want to safely apply the same stash to multiple branches.

Can I stash changes on one branch and apply them on a different branch?

Yes. That is one of the most common use cases. Stash your changes on branch A, switch to branch B, and run git stash apply. Git will apply the diff to the new branch. Conflicts may occur if the branches have diverged significantly in the same files.

How many stashes can I have at once?

There is no hard limit. The stash is a stack (Last In, First Out). stash@{0} is always the most recent. Be careful with a long stash list - old stashes are easy to forget. The best practice is to use descriptive messages and drop stashes as soon as you no longer need them.

Does git stash work with staged changes?

By default, git stash saves both staged and unstaged changes together and unstages everything on restore. If you want to keep your staging area intact, use git stash push --keep-index. This stashes only the unstaged changes and leaves your staged changes in the index ready to commit.

Will git stash affect my commits or push history?

No. Stashes are stored in a separate ref (refs/stash) and are never included in your commit history or pushed to a remote by default. They are purely local. If you want to share work-in-progress across machines, consider a WIP commit on a personal branch instead.

Use our free tool here

Comparing two versions of a file after applying a stash? Our Diff Checker shows side-by-side differences with syntax highlighting - paste any two files and compare instantly.

Use our free tool here →

The Bottom Line

Git stash is an essential tool for any developer who works across multiple concerns simultaneously. Master the key commands - push -m, list, pop, apply, branch - and you will never need to make a throwaway commit just to switch contexts again.

The most important habit: always add a description with git stash push -m "description". An unnamed stash list is a graveyard of forgotten work. And if you are about to apply a stash and are not sure what is in it, use git stash show -p stash@{N} or paste the before/after state into our Diff Checker to preview the changes.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.