Urgent fix in the middle of a refactor
Your working tree is full of moved and new files that you don't want to stash. You add a temporary worktree on main, commit the fix there, and remove the worktree when you're done.
Git · Command
git worktree lets one repository have several working directories, so you can check out more than one branch at once. Its subcommands add, list, lock, unlock, move, remove, prune and repair these linked worktrees.
Last updated
A repository has one main worktree (none if it is bare) and can have any number of linked worktrees. Running add creates a directory for the new worktree plus a private admin folder under $GIT_DIR/worktrees/<id>. The new directory gets a small .git file that points back to that folder. All worktrees share the same objects, refs and config. Each one keeps its own HEAD, index and pseudo-refs. If you omit <commit-ish>, add uses the last part of the path as the branch name and creates that branch from HEAD if it doesn't exist yet.
git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]] [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]
git worktree list [-v | --porcelain [-z]]
git worktree lock [--reason <string>] <worktree>
git worktree move <worktree> <new-path>
git worktree prune [-n] [-v] [--expire <expire>]
git worktree remove [-f] <worktree>
git worktree repair [<path>...]
git worktree unlock <worktree>| Name | Type | Description |
|---|---|---|
<path> | path | Directory where add creates the new worktree. If no branch is given, its last component becomes the branch name. |
<commit-ish> | commit-ish | What to check out in the new worktree. A bare '-' means @{-1} (the previous branch). |
<worktree> | path | Names an existing worktree by relative or absolute path, or by its last path components if they are unique. |
-b / -B <new-branch> | branch name | Creates a new branch at <commit-ish> (HEAD by default) for the worktree. -B resets the branch if it already exists. |
-f / --force | flag | Overrides safety checks: a branch checked out elsewhere, a missing path, or an unclean worktree. Give it twice for locked worktrees. |
-d / --detach | flag | With add, gives the new worktree a detached HEAD instead of a branch. |
--orphan | flag | With add, starts the worktree with an empty tree and index on a new unborn branch. |
--lock / --reason <string> | flag / string | Locks the worktree as soon as it is created, optionally recording why. |
--porcelain / -z | flag | With list, prints machine-readable output; -z ends each line with NUL instead of a newline. |
-n / --dry-run, --expire <time> | flag / time | With prune, reports what would be removed without removing it, or only prunes missing worktrees older than <time>. |
#!/usr/bin/env bash
set -euo pipefail
# Create ../hotfix on a new branch based on main
git worktree add -b hotfix ../hotfix main
# Do the fix there; your current checkout stays as it is
(
cd ../hotfix
echo "fix" >> CHANGELOG.md
git commit -am "Hotfix: patch release"
)
# See every worktree in script-friendly form
git worktree list --porcelain
# Clean up when done (fails if ../hotfix has uncommitted changes)
git worktree remove ../hotfix
# Clear admin data for any worktree folders that were deleted by hand
git worktree prune --verboseThe script commits a hotfix on its own branch in a separate directory, lists all worktrees, then removes the temporary one and prunes leftover entries, all without disturbing the original checkout.
Your working tree is full of moved and new files that you don't want to stash. You add a temporary worktree on main, commit the fix there, and remove the worktree when you're done.
Run git worktree add -d to get a detached worktree for trying out a build or experiment. No branch is created and your current branch is left alone.
Keep long-lived worktrees for a release branch and a feature branch, so you can build and test both at once without switching back and forth.
Keep a worktree on an external drive and lock it with a reason, so automatic pruning doesn't delete its admin data while the drive is unplugged.
Every worktree uses the same object database, the same refs under refs/, and by default the same config file. Each worktree has its own HEAD, index and other pseudo-refs, plus refs under refs/bisect, refs/worktree and refs/rewritten. These per-worktree files live in $GIT_DIR/worktrees/<id>, and $GIT_COMMON_DIR points back to the main .git directory.
Follow-up: How do you read another worktree's HEAD from the one you're in? Use the special ref paths: main-worktree/HEAD for the main worktree, or worktrees/<name>/HEAD for a linked one. Commands like git rev-parse resolve these correctly.
The admin entry under $GIT_DIR/worktrees stays behind, and git worktree list marks it as prunable. Git eventually removes it on its own, depending on gc.worktreePruneExpire. You can also run git worktree prune from any worktree right away, adding -n first to preview what would go.
Follow-up: What if you moved the folder instead of deleting it? Run git worktree repair from inside the moved worktree, or from any worktree with the new path as an argument, and Git rewrites the gitdir links instead of pruning the entry.
Turn on the extension with git config extensions.worktreeConfig true. Then git config --worktree writes to that worktree's own config.worktree file. If core.worktree or core.bare is set in the shared config, move it into the main worktree's config.worktree. Older Git versions can't open repositories that have this extension enabled.
Follow-up: Why can turning on worktreeConfig break a bare repository setup? Once the extension is on, core.bare=true in the shared config no longer applies only to the main worktree, so it affects every worktree; you have to move it into the main worktree's config.worktree.
git-checkoutgit-switchgit-branchgit-stashgit-configgit-rev-parsegit-update-refgitrepository-layout