Git — Stashing & Worktrees
Git stash and worktrees solve two fundamental workflow problems: temporarily setting aside uncommitted work, and working on multiple branches simultaneously without interference.
Stash lets you save your dirty working directory and staging area to a stack of temporary states, while worktrees allow multiple branches to be checked out in separate directories using a single Git repository.
The git stash command temporarily saves your modified tracked files and staged changes so you can work on something else, then reapply them later. Think of it as a clipboard for your working directory.
| 1 | # Stash current changes (tracked files only) |
| 2 | git stash |
| 3 | |
| 4 | # Stash with a descriptive message |
| 5 | git stash push -m "WIP: payment form validation" |
| 6 | |
| 7 | # List all stashes |
| 8 | git stash list |
| 9 | # stash@{0}: On feature/payments: WIP: payment form validation |
| 10 | # stash@{1}: On main: fix login redirect |
| 11 | |
| 12 | # Apply the most recent stash (keep it in stash list) |
| 13 | git stash apply |
| 14 | |
| 15 | # Apply a specific stash |
| 16 | git stash apply stash@{1} |
| 17 | |
| 18 | # Apply and remove from stash list (pop) |
| 19 | git stash pop |
| 20 | |
| 21 | # Drop a specific stash without applying |
| 22 | git stash drop stash@{1} |
| 23 | |
| 24 | # Clear the entire stash list |
| 25 | git stash clear |
info
The --patch flag (or -p) lets you stash individual hunks of changes from a file, rather than the entire file. This is useful when a file contains both work-in-progress and changes you want to commit separately.
| 1 | # Stash only selected hunks interactively |
| 2 | git stash --patch |
| 3 | |
| 4 | # You'll be prompted for each hunk: |
| 5 | # @@ -10,7 +10,7 @@ function validate(form) { |
| 6 | # - const email = form.email.value; |
| 7 | # + const email = form.email.value.trim(); |
| 8 | # Stage this hunk [y,n,q,a,d,/,s,e,?]? |
| 9 | |
| 10 | # Options: |
| 11 | # y - stash this hunk |
| 12 | # n - don't stash this hunk |
| 13 | # s - split this hunk into smaller hunks |
| 14 | # q - quit (don't stash remaining hunks) |
| 15 | # a - stash this hunk and all remaining hunks |
| 16 | # d - don't stash this hunk or any later hunks |
| 17 | # ? - print help |
After partial stashing, you can commit the unstaged changes (which represent the clean, ready-to-commit portion) and later reapply the stashed work.
By default, git stash only stashes tracked files — files that Git is already aware of. To include untracked files (new files not yet added), use the -u or --include-untracked flag.
| 1 | # Stash tracked + untracked files |
| 2 | git stash --include-untracked |
| 3 | # Short form: |
| 4 | git stash -u |
| 5 | |
| 6 | # Stash everything including ignored files |
| 7 | git stash --all |
| 8 | # WARNING: This stashes node_modules/, .env, etc. |
| 9 | # Use with extreme caution |
| 10 | |
| 11 | # Check that untracked files were stashed |
| 12 | git stash list |
| 13 | git stash show -p stash@{0} | head -20 |
warning
The git stash command also accepts the --index flag, which tells Git to try to reapply both the staged (index) and unstaged (working tree) changes separately when applying the stash.
| 1 | # Stash including the index state |
| 2 | git stash --index |
| 3 | |
| 4 | # When applying, Git restores: |
| 5 | # - Staged changes back to the staging area |
| 6 | # - Unstaged changes back to the working directory |
| 7 | |
| 8 | # This is useful when you have partially staged files |
| 9 | git add config.js # staged |
| 10 | # edit src/app.js # unstaged |
| 11 | git stash --index # saves both states separately |
| 12 | git stash apply --index # restores both correctly |
If you stash changes and later realize they should live on a different branch, git stash branch creates a new branch based on the commit where the stash was originally created, applies the stash, and drops it from the stash list.
| 1 | # Create a new branch from the stash commit and apply |
| 2 | git stash branch new-feature stash@{0} |
| 3 | |
| 4 | # This is equivalent to: |
| 5 | # 1. git checkout <commit-where-stash-was-made> |
| 6 | # 2. git checkout -b new-feature |
| 7 | # 3. git stash apply stash@{0} |
| 8 | # 4. git stash drop stash@{0} |
| 9 | |
| 10 | # If your current branch has diverged significantly: |
| 11 | # The stash might not apply cleanly. |
| 12 | # Using git stash branch avoids conflicts by starting |
| 13 | # from the exact state where the stash was created. |
| 14 | |
| 15 | # Apply to current branch (if compatible): |
| 16 | git stash apply stash@{0} |
pro tip
A Git worktree allows you to check out multiple branches simultaneously in separate directories, all sharing the same Git repository (objects, refs). This eliminates the need to stash changes or clone the repo multiple times.
Worktrees share the .gitdirectory's object store and references, so disk usage is minimal — only the checked-out files in each worktree take additional space.
| 1 | # List all worktrees |
| 2 | git worktree list |
| 3 | # /Users/me/project main [abc1234] |
| 4 | # /Users/me/project-hotfix hotfix [def5678] |
| 5 | # /Users/me/project-feature feature [ghi9012] |
| 6 | |
| 7 | # Add a new worktree (creates directory and checks out branch) |
| 8 | git worktree add ../project-hotfix hotfix |
| 9 | |
| 10 | # Add a worktree for a new branch |
| 11 | git worktree add -b new-feature ../project-feature main |
| 12 | |
| 13 | # Remove a worktree |
| 14 | git worktree remove ../project-hotfix |
| 15 | |
| 16 | # Prune stale worktree references (after manual deletion) |
| 17 | git worktree prune |
Worktrees can be created from existing branches or new branches. Each worktree has its own working directory, index, and HEAD reference, allowing completely independent work.
| 1 | # Create worktree from existing branch |
| 2 | git worktree add /path/to/hotfix-fix bugfix-123 |
| 3 | |
| 4 | # Create worktree with a new branch based on main |
| 5 | git worktree add -b feature/dashboard /path/to/dashboard main |
| 6 | |
| 7 | # Create worktree from a tag (detached HEAD) |
| 8 | git worktree add /path/to/release-v2 v2.0.0 |
| 9 | |
| 10 | # Lock a worktree to prevent pruning |
| 11 | git worktree lock /path/to/hotfix-fix --reason "Active hotfix" |
| 12 | |
| 13 | # Unlock a worktree |
| 14 | git worktree unlock /path/to/hotfix-fix |
| 15 | |
| 16 | # Move a worktree to a new location |
| 17 | git worktree move /path/to/old /path/to/new |
| 18 | |
| 19 | # Get detailed info about a worktree |
| 20 | git worktree list --porcelain |
info
Reviewing Pull Requests
Create a worktree from a colleague's feature branch to review their code locally without disturbing your current work. When done, simply remove the worktree.
Hotfix While Working on Features
A production bug appears while you're deep in a feature branch. Create a worktree from main, fix the bug, commit, push, and delete the worktree — all without stashing or interrupting your feature work.
Running Parallel CI/Test Environments
Run tests on different branches simultaneously by creating worktrees for each branch. This is especially useful for monorepos where different packages need testing on different branches.
Long-Running Experiments
Keep an experimental branch checked out in a separate worktree, allowing you to work on it whenever inspiration strikes without context-switching your main working directory.
Keep Stashes Temporary
A stash should be short-lived — a few hours at most. If a stash sits for days, create a branch instead. Stashes are not a replacement for branches; they are a temporary scratch pad.
Name Your Stashes
Always use git stash push -m with a descriptive message. Without names, stashes are just stash@{N} entries that become cryptic once you have more than a few.
Worktrees Over Multiple Clones
Use worktrees instead of cloning the repository multiple times. Worktrees share the object store, saving disk space and ensuring you never forget to git fetch in one of the clones.
Prune Stale Worktrees
Run git worktree prune periodically or after manually deleting a worktree directory to keep the worktree list clean and avoid confusion.