You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
5.9 KiB
Markdown
171 lines
5.9 KiB
Markdown
# Git Worktrees
|
|
|
|
## What Are They?
|
|
|
|
A git worktree is a checked-out copy of a branch that lives in a separate directory on your filesystem, but shares the same underlying git repository (`.git` database) as your main clone.
|
|
|
|
Normally, a single git clone has one working directory — the files you see and edit. A worktree lets you have **multiple working directories at once**, each on a different branch, all tied to the same repository. You don't clone the repo a second time; you project a second (or third, or fourth) working directory from the one clone.
|
|
|
|
```
|
|
~/.git/ ← shared: all objects, refs, config
|
|
~/projects/myapp/ ← main worktree (branch: main)
|
|
~/projects/myapp-feature/ ← linked worktree (branch: feature/auth)
|
|
~/projects/myapp-hotfix/ ← linked worktree (branch: hotfix/crash)
|
|
```
|
|
|
|
All three directories above read and write to the same `.git` object store. Commits made in any worktree are immediately visible to all others.
|
|
|
|
---
|
|
|
|
## Core Commands
|
|
|
|
### Add a worktree
|
|
|
|
```sh
|
|
# Check out an existing branch into a new directory
|
|
git worktree add ../myapp-feature feature/auth
|
|
|
|
# Create a new branch and check it out in one step
|
|
git worktree add -b feature/new-thing ../myapp-new-thing main
|
|
```
|
|
|
|
The first argument is the path for the new directory. The second is the branch name (or starting commit).
|
|
|
|
### List worktrees
|
|
|
|
```sh
|
|
git worktree list
|
|
```
|
|
|
|
Example output:
|
|
|
|
```
|
|
/home/you/projects/myapp abc1234 [main]
|
|
/home/you/projects/myapp-feature def5678 [feature/auth]
|
|
```
|
|
|
|
### Remove a worktree
|
|
|
|
```sh
|
|
# Remove the directory and deregister the worktree
|
|
git worktree remove ../myapp-feature
|
|
|
|
# Force-remove even if there are untracked or modified files
|
|
git worktree remove --force ../myapp-feature
|
|
```
|
|
|
|
After deleting a linked worktree directory manually (e.g. with `rm -rf`), git still knows about it. Clean up the stale reference with:
|
|
|
|
```sh
|
|
git worktree prune
|
|
```
|
|
|
|
### Move a worktree
|
|
|
|
```sh
|
|
git worktree move ../myapp-feature ../myapp-auth-feature
|
|
```
|
|
|
|
---
|
|
|
|
## Typical Workflows
|
|
|
|
### Work on two branches simultaneously
|
|
|
|
You're deep in a feature branch when a urgent bug report comes in. Instead of stashing your work or committing a WIP, you add a worktree:
|
|
|
|
```sh
|
|
git worktree add ../myapp-hotfix main
|
|
cd ../myapp-hotfix
|
|
# fix the bug, commit, push — then come back to your feature
|
|
```
|
|
|
|
Your feature working directory is untouched.
|
|
|
|
### Run tests against a different branch without switching
|
|
|
|
```sh
|
|
git worktree add /tmp/myapp-test origin/release/2.0
|
|
cd /tmp/myapp-test
|
|
cargo test
|
|
```
|
|
|
|
You keep your editor open on `main` while tests run elsewhere.
|
|
|
|
### Review a colleague's PR locally
|
|
|
|
```sh
|
|
git fetch origin
|
|
git worktree add ../review-pr-123 origin/pr/123
|
|
cd ../review-pr-123
|
|
# read, run, evaluate — then remove when done
|
|
git worktree remove ../review-pr-123
|
|
```
|
|
|
|
---
|
|
|
|
## How It Works Internally
|
|
|
|
When you run `git worktree add`, git:
|
|
|
|
1. Creates a subdirectory inside `.git/worktrees/<name>/` to store the worktree's private state (its `HEAD`, index, and a back-reference to the working directory path).
|
|
2. Writes a `.git` *file* (not a directory) into the new working directory that points back to `.git/worktrees/<name>/`.
|
|
3. Checks out the requested branch into the new directory.
|
|
|
|
The object database (all commits, trees, blobs) is shared. Only the index and `HEAD` are per-worktree.
|
|
|
|
---
|
|
|
|
## Limitations and When to Avoid Them
|
|
|
|
### Each branch can only be checked out once
|
|
|
|
The most important constraint: **a single branch cannot be checked out in two worktrees at the same time.** Git enforces this to prevent the two trees from diverging their indexes silently. If you try, you'll get an error:
|
|
|
|
```
|
|
fatal: 'feature/auth' is already checked out at '/home/you/projects/myapp'
|
|
```
|
|
|
|
Workaround: check out the second worktree at a specific commit (detached HEAD), or create a local tracking branch.
|
|
|
|
### Tools that look for `.git` as a directory can break
|
|
|
|
Some tools assume `.git` is a directory, not a file. A linked worktree has a `.git` *file* instead, which confuses:
|
|
|
|
- Older git GUIs that scan for `.git/` directories
|
|
- Some shell prompts and plugins that detect git repos naively
|
|
- Scripts that do `test -d .git`
|
|
|
|
### Build systems that use the working directory path
|
|
|
|
If your build system or language tooling caches absolute paths (e.g. Cargo's `target/` directory is placed relative to the workspace root), separate worktrees work fine — each has its own `target/` directory. But if a tool bakes the source path into cached artifacts, switching between worktrees may cause spurious rebuilds or cache invalidation.
|
|
|
|
### Hooks run in the worktree context, not the main repo
|
|
|
|
Git hooks in `.git/hooks/` apply to all worktrees. But the working directory (`$GIT_WORK_TREE`) will be the linked worktree path, not the main repo path. Hook scripts that assume a fixed working directory can behave unexpectedly.
|
|
|
|
### Not a substitute for branches in CI
|
|
|
|
Worktrees are a local developer convenience. Don't model CI pipelines around them — use proper branch checkouts in ephemeral CI environments instead.
|
|
|
|
### Submodules require extra care
|
|
|
|
Submodules are not automatically initialized in a new worktree. You need to run `git submodule update --init` inside each linked worktree where you need them.
|
|
|
|
### Avoid for long-lived parallel development
|
|
|
|
If you find yourself maintaining two worktrees of the same repo for weeks at a time, that's a signal you might want two separate clones or a proper branch strategy — not worktrees. Worktrees shine for short-lived parallel work (hotfixes, reviews, quick tests), not as a permanent parallel development setup.
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
| Task | Command |
|
|
|---|---|
|
|
| Add a worktree for an existing branch | `git worktree add <path> <branch>` |
|
|
| Add a worktree and create a new branch | `git worktree add -b <branch> <path> <start-point>` |
|
|
| List all worktrees | `git worktree list` |
|
|
| Remove a worktree | `git worktree remove <path>` |
|
|
| Clean up stale worktree records | `git worktree prune` |
|
|
| Move a worktree | `git worktree move <old-path> <new-path>` |
|