Skip to content

Stashing and the Worktree

You're halfway through a feature when an urgent bug comes in. Your working directory has uncommitted changes that aren't ready for a commit. You need to switch context, fix the bug, and come back to where you left off. Git provides two tools for this: stashing saves changes temporarily and restores them later, and worktrees let you work on multiple branches simultaneously in separate directories.


Git Stash

git stash takes your modified tracked files and staged changes, saves them on a stack, and reverts your working directory to match HEAD. You can then switch branches, do other work, and come back to apply the stashed changes.

Basic Stash Workflow

# Save current changes to the stash
git stash

# Same as above, with a descriptive message
git stash push -m "WIP: user profile validation"

# List all stashes
git stash list

# Apply the most recent stash (keep it in the stack)
git stash apply

# Apply and remove the most recent stash
git stash pop

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

What Gets Stashed

By default, git stash saves:

  • Modified tracked files
  • Staged changes

It does not stash:

  • Untracked files (new files not yet added)
  • Ignored files

Use flags to include those:

# Include untracked files
git stash push -u
# or
git stash push --include-untracked

# Include everything (untracked + ignored)
git stash push -a
# or
git stash push --all

Inspecting Stashes

# List all stashes with their messages
git stash list
# stash@{0}: On feature/auth: WIP: user profile validation
# stash@{1}: WIP on main: a1b2c3d Fix login bug
# stash@{2}: On feature/search: search index prototype

# Show what a stash contains (as a diff)
git stash show
# src/auth.py | 12 ++++++------
# src/user.py |  8 ++++++++

# Show the full diff
git stash show -p

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

Dropping Stashes

# Drop the most recent stash
git stash drop

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

# Clear all stashes
git stash clear

Stashes can be lost

git stash drop and git stash clear permanently remove stashes. Unlike commits, dropped stashes are difficult to recover (possible only through git fsck --lost-found if you act quickly). Don't use the stash as long-term storage - commit your work or create a branch.

Creating a Branch from a Stash

If your stashed changes conflict with work done since stashing, or if you realize the stashed work deserves its own branch:

# Create a new branch from where you stashed, apply the stash, and drop it
git stash branch new-branch-name

# From a specific stash
git stash branch new-branch-name stash@{2}

This creates the branch at the commit where the stash was originally created, applies the stash, and drops it if the apply succeeds.

Invalid interactive component configuration (terminal)


Git Worktree

Stashing works for quick context switches, but has limits. If you need to work on two branches simultaneously - reviewing a pull request while coding a feature, running tests on one branch while developing on another - you need separate working directories. That's what git worktree provides.

A worktree is an additional working directory linked to the same repository. Each worktree has its own checked-out branch, its own staging area, and its own working files, but they all share the same .git object database. Changes committed in any worktree are immediately available to all others.

Creating a Worktree

# Create a worktree for an existing branch
git worktree add ../project-hotfix hotfix/urgent-fix

# Create a worktree with a new branch
git worktree add -b feature/new-search ../project-search

# Create a worktree at a specific commit (detached HEAD)
git worktree add ../project-review a1b2c3d

The first argument is the directory path for the new worktree. The second is the branch or commit to check out.

Listing and Removing Worktrees

# List all worktrees
git worktree list
# /home/user/project         a1b2c3d [main]
# /home/user/project-hotfix  b2c3d4e [hotfix/urgent-fix]
# /home/user/project-search  c3d4e5f [feature/new-search]

# Remove a worktree (after you're done with it)
git worktree remove ../project-hotfix

# Clean up stale worktree references
git worktree prune

Rules and Constraints

  • Each branch can only be checked out in one worktree at a time
  • The main worktree (the original clone) can't be removed with git worktree remove
  • All worktrees share the same object database, refs, and config
  • git worktree lock prevents a worktree from being pruned (useful for worktrees on removable drives)

Stash vs Worktree: When to Use Which

Situation Use Stash Use Worktree
Quick context switch (minutes) Yes Overkill
Working on two branches simultaneously No Yes
Reviewing a PR while developing No Yes
Running long tests on one branch while coding on another No Yes
Saving work-in-progress before pulling Yes No
Need separate build artifacts per branch No Yes
One-off "save and restore" Yes Overkill

Git Clean

git clean removes untracked files from your working directory. It's useful for resetting to a pristine state - removing build artifacts, generated files, or other clutter that isn't tracked by Git.

# Dry run - show what would be removed (always do this first)
git clean -n

# Remove untracked files
git clean -f

# Remove untracked files and directories
git clean -fd

# Remove untracked and ignored files (full reset)
git clean -fdx

# Interactive mode - choose what to remove
git clean -i

git clean is irreversible

git clean -f permanently deletes files. There's no undo, no stash, no reflog for untracked files. Always run git clean -n (dry run) first to see what will be removed.

The flags:

Flag Effect
-n Dry run (show what would be removed)
-f Force (required for actual deletion)
-d Include untracked directories
-x Also remove ignored files (build artifacts, etc.)
-X Remove only ignored files (keep untracked)
-i Interactive mode

git clean -fdx is the nuclear option - it removes everything not tracked by Git, including files in .gitignore. Useful for getting a completely clean slate before a release build.


Exercises


Further Reading


Previous: Rewriting History | Next: Configuring Git | Back to Index

Comments