Two situations come up constantly in day-to-day Git work: needing to set aside unfinished work to deal with something else without committing half-done changes, and needing to remove files from your working directory that should not be there. git stash and git clean are the tools for each of these.
The Problem Stashing Solves
Imagine you are mid-way through working on a feature. Your working directory has changes — some staged, some not — and none of it is ready to commit. An urgent task comes in and you need to switch branches. Git may refuse the switch if your uncommitted changes would conflict with the target branch.
Committing half-done work just to clear the way is not the answer — it pollutes your history with incomplete commits. git stash solves this by saving your dirty working directory state onto a temporary stack so you can return to a clean state, handle the interruption, and restore your work exactly where you left off.
Stashing Your Work — git stash
To stash all current changes — both staged and modified tracked files:
git stash
# or equivalently:
git stash push
Git saves the state of your working directory and staging area, then reverts both to match the last commit:
Saved working directory and index state WIP on main: 049d078 Create index file
HEAD is now at 049d078 Create index file
Running git status now shows a clean working directory. You can freely switch branches, handle the urgent work, and come back.
Note:
git stash saveis an older syntax that does the same thing. It has been deprecated in favour ofgit stash push, which supports more options. You will still encountergit stash savein older tutorials — both work, but prefergit stash pushfor new work.
Listing Stashes — git stash list
Stashes are stored on a stack — you can accumulate multiple stashes. To see all of them:
git stash list
stash@{0}: WIP on main: 049d078 Create index file
stash@{1}: WIP on main: c264051 Revert "Add file_size"
stash@{2}: WIP on main: 21d80a5 Add number to log
Each stash is identified by stash@{n} where 0 is the most recent. The message shows the branch and commit it was created from.
Applying a Stash — git stash apply
To restore a stash without removing it from the stack:
git stash apply # Apply the most recent stash
git stash apply stash@{2} # Apply a specific stash by reference
Git re-modifies the files to restore the working directory to the stashed state. The stash remains on the stack — apply does not remove it.
Restoring the staging area too
By default, git stash apply restores modified files but does not re-stage files that were staged at the time of the stash. To restore the staging area as well:
git stash apply --index
This brings your working directory and staging area back to exactly the state they were in when you stashed.
Removing a Stash — git stash drop and git stash pop
apply leaves the stash on the stack. To remove a stash explicitly:
git stash drop stash@{0} # Remove a specific stash
The most common pattern — apply and immediately remove — is handled by a single command:
git stash pop # Apply the most recent stash and drop it
After pop, the stash is gone from the list and your working directory has the restored changes.
Stash Variants
Stash with a message
By default, the stash message is auto-generated from the branch and last commit. To write a descriptive message:
git stash push -m "WIP: refactoring auth middleware"
This makes git stash list much more readable when you have multiple stashes.
Stash only unstaged changes — --keep-index
To stash only the unstaged changes while leaving staged changes intact:
git stash --keep-index
Useful when you want to test that your staged changes work in isolation.
Include untracked files — -u
By default, git stash only stashes tracked files. To include untracked files:
git stash -u
# or:
git stash --include-untracked
To include both untracked and ignored files:
git stash -a
# or:
git stash --all
Partial stash — --patch
Like git add -p, stash can be applied selectively. Git will walk through each changed hunk and ask whether to stash it:
git stash --patch
Creating a Branch from a Stash
If you stashed work on a branch that has since moved forward, applying the stash may produce conflicts. A cleaner approach is to create a new branch from the stash — Git checks out the commit you were on when you stashed, applies the stash there, and drops it if successful:
git stash branch new-branch-name
git stash branch new-branch-name stash@{2} # From a specific stash
This is the cleanest way to resume stashed work when the original branch has changed significantly.
Clearing All Stashes
To remove all stashes at once:
git stash clear
⚠️ This permanently removes all stashes. There is no recovery.
Cleaning the Working Directory — git clean
Where git stash saves changes for later, git clean permanently removes them. It is designed to delete untracked files from your working directory — files Git is aware of but has never been told to track.
Common reasons to clean:
- Removing build artifacts before a fresh build.
- Clearing generated files left behind by merge tools.
- Resetting the working directory to a pristine state.
⚠️
git cleandeletes files permanently. Unlikegit restore, there is no recovery. Always do a dry run first.
Dry run — -n
See what would be removed without actually deleting anything:
git clean -n
Would remove debug.log
Would remove temp/
Always run this before the actual clean.
Removing untracked files — -f
The -f flag (force) is required because Git protects you from accidental deletion:
git clean -f
Removing untracked files and directories — -f -d
By default, git clean only removes files, not directories. To also remove untracked directories:
git clean -f -d
Removing ignored files too — -x
To remove files that are ignored by .gitignore as well (build output, node_modules, etc.):
git clean -f -x # Remove untracked and ignored files
git clean -f -d -x # Remove untracked files, directories, and ignored files
Interactive mode — -i
For a safer, guided clean that lets you confirm each deletion:
git clean -i
git stash --all as a Safer Alternative to git clean
If you want to remove untracked files but are not certain you want to discard them permanently, git stash --all is a safer alternative — it removes everything but saves it in a stash so you can recover if needed:
git stash --all
Summary
| Command | What It Does |
|---|---|
git stash | Stashes staged and modified tracked changes |
git stash push -m "msg" | Stashes with a descriptive message |
git stash -u | Stashes including untracked files |
git stash -a | Stashes including untracked and ignored files |
git stash --keep-index | Stashes only unstaged changes |
git stash --patch | Interactively chooses which changes to stash |
git stash list | Lists all stashes |
git stash apply | Applies the most recent stash (keeps it on the stack) |
git stash apply --index | Applies stash and restores the staging area |
git stash pop | Applies the most recent stash and removes it |
git stash drop stash@{n} | Removes a specific stash |
git stash clear | Removes all stashes (destructive) |
git stash branch <name> | Creates a new branch from a stash |
git clean -n | Dry run — shows what would be removed |
git clean -f | Removes untracked files (destructive) |
git clean -f -d | Removes untracked files and directories |
git clean -f -x | Removes untracked and ignored files |
git clean -i | Interactive clean |