Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 022 / 100

git stash: what every Git & GitHub developer should know

Park work temporarily.

Expona Admin8 min read

We've all been there: you're mid-feature when a critical bug lands in production, or your lead asks you to switch contexts to review someone else's work. You don't want to commit half-baked code, and you certainly don't want to lose your progress. That's where git stash comes in. Understanding git stash: what every Git & GitHub developer should know will save you time, reduce context-switching friction, and keep your commit history clean.

What is git stash and why it matters

Git stash is a built-in command that temporarily saves your working directory changes—both staged and unstaged—without committing them. Think of it as a temporary clipboard for your code. When you run stash, your current branch reverts to the last commit, and your changes are stored in a separate stack that you can retrieve later.

In a typical week, you'll encounter situations where stashing is invaluable. A teammate asks for help debugging their branch. Your product manager wants you to demo a feature on main. A critical hotfix needs your attention right now. Without stash, you'd either lose work or litter your history with throwaway commits. With it, you switch context cleanly and return to exactly where you left off.

git stash push -m "message": capturing work with context

The foundation of effective stashing is naming your work. The command git stash push -m "message" lets you save your changes with a descriptive label, making it trivial to find the right stash later.

Here's how it works in practice:

bash
$ git status
On branch feature/user-auth
Changes not staged for commit:
  modified:   src/auth.ts
  modified:   src/components/Login.tsx

$ git stash push -m "WIP: add passwordless login via magic links"
Saved working directory and index state On branch feature/user-auth WIP: add passwordless login via magic links

$ git status
On branch feature/user-auth
nothing to commit, working tree clean

Notice what happened: your branch is now clean. You can safely check out another branch, run tests, or deploy code without any uncommitted changes interfering. The -m flag is critical—it transforms a generic "WIP stash" into a named checkpoint. Six months later, when you're searching through stashes, you'll thank yourself for the clear message instead of "WIP on feature/user-auth".

Compare this to the older syntax git stash save "message", which still works but is less explicit. Using push makes the intent clearer: you're actively pushing work onto the stash stack.

git stash list and git stash pop: retrieving your work

Stashing only helps if you can easily find and restore your work. That's where git stash list and git stash pop come in.

First, list your stashes:

bash
$ git stash list
stash@{0}: On branch feature/user-auth WIP: add passwordless login via magic links
stash@{1}: On branch feature/payments WIP: implement Stripe webhook retry logic
stash@{2}: On branch main WIP: update dependencies

Each stash is indexed. The newest is stash@{0}, and older ones follow. The reference always includes the branch it was created on and your message, so you can quickly identify which one you need.

Now retrieve your work. The simplest approach is to pop the most recent stash:

bash
$ git stash pop
On branch feature/user-auth
Changes not staged for commit:
  modified:   src/auth.ts
  modified:   src/components/Login.tsx

Dropped stash@{0} (abc12345defgh...)

Pop combines two operations: it applies the stash and removes it from the stack. Your files are back, exactly as you left them.

If you want to apply a stash without removing it from the list, use apply instead:

bash
$ git stash apply stash@{1}

This is useful when you need the same changes on multiple branches, though that scenario is relatively rare in day-to-day work. Most of the time, pop is what you want—it's cleaner and prevents stash stack clutter.

If you accidentally pop the wrong stash or realize you need it again later, remember that Git keeps a reflog. You can usually recover it with git reflog and cherry-pick the commit hash, but avoiding the mistake in the first place is better. Take the time to read your stash list carefully.

Include untracked files with -u

By default, git stash only saves tracked files—ones that Git knows about from a previous commit. New files you've created are left behind in your working directory. This can cause problems.

Imagine you've created a new service file that's part of your feature:

bash
$ git status
On branch feature/analytics
Changes not staged for commit:
  modified:   src/services/tracking.ts
Untracked files:
  src/services/eventQueue.ts

$ git stash push -m "WIP: event tracking refactor"
Saved working directory and index state On branch feature/analytics: WIP: event tracking refactor

$ git status
On branch feature/analytics
Untracked files:
  src/services/eventQueue.ts

Your new file is still there. If you switch branches or pull changes, that file might conflict or cause unexpected behavior. The solution is simple: use the -u flag (short for --include-untracked):

bash
$ git stash push -u -m "WIP: event tracking refactor"
Saved working directory and index state On branch feature/analytics: WIP: event tracking refactor

$ git status
On branch feature/analytics
nothing to commit, working tree clean

Now both your modified files and your new files are stashed. When you pop, everything returns. This is especially important when building features that introduce new modules, components, or configuration files.

A practical habit: use -u by default. It rarely causes problems and prevents the common frustration of "where did my new file go?" The only exception is if you have genuine build artifacts or generated files you want to leave behind, but those should be in .gitignore anyway.

Prefer WIP commits on branches for long pauses

Stash is powerful, but it's not the right tool for every situation. When you're pausing work for more than a few hours, or when you might need to return to it on a different machine, a Work-In-Progress commit on a branch is often better.

Here's the difference:

Scenario Use stash Use WIP commit
Pausing for 15 minutes to help a teammate ✓ Yes Overkill
Switching to a hotfix, returning in an hour ✓ Yes Either works
Pausing a complex feature for a day or more ✓ Risky ✓ Better
Sharing work with your team or a different machine ✗ Can't push stash ✓ Yes, push the branch
Work that needs review or discussion ✗ Not shared ✓ Open a draft PR

When your pause is long, a WIP commit gives you several advantages:

  • Persistence: Stashes are local and can be lost if you reset or corrupt your repository. Commits are safer.
  • Shareability: Push your branch and your teammates can pull it, review it, or build on it.
  • Visibility: A draft PR makes your work visible and prevents duplicate effort.
  • History: If something goes wrong, you have a clear commit to reference.

Here's how to do it:

bash
$ git add .
$ git commit -m "WIP: event tracking refactor - in progress, do not merge"
$ git push origin feature/analytics

Later, when you're ready to continue:

bash
$ git pull origin feature/analytics
$ # ... keep working
$ git commit --amend -m "Add event tracking refactor"  # Clean up the WIP message when done
$ git push

Some teams enforce a convention where WIP commits are rewritten out before merging (via squash or rebase). Others allow them in the history. The key is that your work is safe, shared, and recoverable.

Common mistakes

Forgetting which stash is which: Without meaningful messages, your stash list becomes noise. Always use -m. If you find yourself with a backlog of mysterious stashes, spend an hour popping them one by one, reviewing, and either committing or discarding.

Leaving stashes behind: Stash is temporary by design. A stash that sits for weeks is a sign you should have made a proper commit instead. Periodically clean up: git stash drop stash@{N} removes a specific stash. git stash clear nukes them all—use with care.

Stashing with untracked files forgotten: As discussed, forgetting -u leads to orphaned files in your working directory. Make it a habit to run git status before stashing, and use -u unless you have a specific reason not to.

Stashing staged changes only: By default, git stash stashes both staged and unstaged changes. If you only want to stash unstaged changes (leaving staged ones), use git stash push --keep-index. This is rarely needed but occasionally useful when you've carefully staged a subset of changes and want to test them in isolation.

Pop conflicts: If you've made changes on your branch since you stashed, popping can cause merge conflicts. When this happens, resolve them as you would any merge conflict, then git add and git status to confirm the stash was fully applied.

Key takeaways

  • git stash push -m "message" is your primary tool for temporarily parking work with a clear label.
  • git stash list shows all stashes; git stash pop retrieves and removes the most recent one.
  • Always use -u to include untracked files unless you have a specific reason to leave them behind.
  • For pauses longer than a few hours or work that needs to be shared, use a WIP commit on a branch instead of stash.
  • Stash is for quick context switches; commits are for actual checkpoints in your work.
  • Keep your stash list clean. Old stashes are technical debt.
  • Combine stash with clear branch names and PR descriptions for a smooth workflow across your team.

Mastering stash eliminates a common source of friction in daily development. The next time you need to context-switch, you'll do it confidently, knowing your work is safe and you won't clutter your history.

ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles