Git: Stashing and Worktrees

Sometimes you're in the middle of work and need to switch contexts — a colleague needs a quick review, there's an urgent bug, or you just need a clean state temporarily. git stash sets your work aside without committing. git worktree goes further: it lets you check out multiple branches simultaneously in separate directories. git sparse-checkout lets you work with only a subset of a large repository.

Commands Covered

git stash · git worktree · git sparse-checkout

git stash

Saves dirty working tree state (staged and unstaged changes) onto a stack, then reverts to a clean HEAD. You can pop the stash later to restore your work.

# Stash current changes (tracked files only)
$ git stash
$ git stash push

# Stash with a descriptive message
$ git stash push -m "WIP: half-finished auth refactor"

# Include untracked files in the stash
$ git stash push -u
$ git stash push --include-untracked

# Include ignored files too
$ git stash push -a
$ git stash push --all

# Stash only specific files
$ git stash push -- src/auth.c src/session.c

# List all stashes
$ git stash list
# stash@{0}: WIP on main: abc1234 Fix login bug
# stash@{1}: WIP: half-finished auth refactor
# stash@{2}: WIP on feature: def5678 Add search

# Apply the most recent stash (keeps it in the stash list)
$ git stash apply
# Apply a specific stash
$ git stash apply stash@{2}

# Pop the most recent stash (apply and remove from list)
$ git stash pop
# Pop a specific stash
$ git stash pop stash@{1}

# Show what's in a stash (diff)
$ git stash show -p
$ git stash show -p stash@{1}

# Show stash as a list of files
$ git stash show --stat

# Drop (delete) a stash without applying
$ git stash drop stash@{1}

# Clear all stashes
$ git stash clear

Creating a Branch from a Stash

# If applying a stash causes conflicts (context changed since you stashed):
$ git stash branch new-branch-name stash@{0}
# Creates a new branch from the commit the stash was based on,
# applies the stash to it, and drops the stash if successful.

Stash Partial Changes

# Stash interactively — choose which hunks to stash
$ git stash push -p
# Same y/n/s prompts as git add -p

git worktree

Allows you to check out multiple branches simultaneously, each in its own directory. All worktrees share the same .git directory. Useful when you need to compare branches side-by-side, work on a hotfix without stashing, or run tests on multiple branches simultaneously.

# Add a new worktree for a branch
$ git worktree add ../hotfix-dir hotfix-branch
# Creates a new directory ../hotfix-dir checked out to hotfix-branch

# Add a worktree and create a new branch at the same time
$ git worktree add -b emergency-fix ../emergency ../main

# List all worktrees
$ git worktree list
# /home/user/my-repo         abc1234 [main]
# /home/user/hotfix-dir      def5678 [hotfix-branch]
# /home/user/emergency       ghi9012 [emergency-fix]

# Remove a worktree (must be done from the main worktree)
$ git worktree remove ../hotfix-dir
# Or manually delete the directory, then:
$ git worktree prune

# Lock a worktree (prevent accidental removal)
$ git worktree lock ../hotfix-dir --reason "In active use by CI"
$ git worktree unlock ../hotfix-dir

Worktree Rules

# Each branch can only be checked out in one worktree at a time.
# Trying to check out an active branch in a second worktree fails:
$ git worktree add ../copy main
# fatal: 'main' is already checked out at '/home/user/my-repo'

# You CAN check out different branches simultaneously:
# Main worktree: main
# Extra worktree: feature-login
# Extra worktree: hotfix-v2

# Detached HEAD works in worktrees:
$ git worktree add --detach ../review abc1234

git sparse-checkout

Lets you check out only a subset of files from a large repository. Useful when a monorepo is too large to fully check out, or when you only need part of a repo.

# Enable sparse-checkout (cone mode — the simpler, faster mode)
$ git sparse-checkout init --cone

# Set which directories to check out
$ git sparse-checkout set src/api src/web
# Now only src/api/ and src/web/ are checked out; other dirs are absent

# Add more directories
$ git sparse-checkout add src/shared

# List current sparse-checkout patterns
$ git sparse-checkout list

# Disable sparse-checkout (restore full checkout)
$ git sparse-checkout disable

# Non-cone mode (pattern-based, more flexible but slower)
$ git sparse-checkout init
$ git sparse-checkout set '/*' '!/docs/'   # everything except docs/

# Combined with --depth for minimal clone of a large repo:
$ git clone --depth 1 --filter=blob:none --sparse https://github.com/large/repo.git
$ cd repo
$ git sparse-checkout init --cone
$ git sparse-checkout set src/module-i-need

References