How it works, and what it promises.
The numbers, the mechanism, and every place the promise stops. The front page is the short version.
The numbers
What one worktree of the Linux kernel costs.
The same repository, the same command, run twice. The only thing that changes is how much disk the filesystem has to hand out.
| Workload | git worktree add | git sprout add |
|---|---|---|
| Linux kernel, 95 299 files, 2.0 GB | 1816 MB | 36 MB |
| 250 MB, 2000 files | 0.85s · 251 MB | 0.21s · ~0 MB |
| 188 MB, 3000 files, source 6 commits behind | 0.83s · 187 MB | 0.15s · ~1.5 MB |
| btrfs, 188 MB | 0.33s · 187 MB | 0.05s · 0.1 MB |
| ext4 (no block cloning) | 0.41s · 187 MB | falls back, identical |
Five worktrees each across a team of ten is 90 GB of kernel checkouts today, and about 2 GB after.
This will not make your worktrees faster. On a small repository it saves well under a second, and on the kernel the two commands finish within half a second of each other. Cloning in parallel is future work. Install it for the disk column, which holds at every size — what it costs you scales with how many files you have, not how big they are.
The filesystem's own accounting: btrfs filesystem du, verbatim
Total Exclusive Set shared Filename
187.00MiB 0.00B 187.00MiB repo/src <- source
187.00MiB 0.00B 187.00MiB wt-sprout/src <- git sprout add
187.00MiB 187.00MiB 0.00B wt-plain/src <- git worktree add
Provisional figures. The kernel row is measured on the implementation itself, on a dedicated APFS image so nothing else on the machine could contaminate it; the smaller rows are still the research prototype's. Machine: Apple M2, 8 cores, macOS 26.6.1, git 2.55.0; Linux figures on kernel 7.0.12, git 2.47.3, loopback btrfs and XFS. They are re-measured by the benchmark harness in the repository and replaced here at release; the harness and its raw output are in the repo.
How it works
Where your new worktree gets its files.
Four steps. Git still performs the ones that decide what ends up in your worktree.
- Git creates the worktree, empty.
- Every file that is identical in a checkout you already have is cloned by the filesystem into a new file that shares the same disk blocks until something writes to it.
- A file is only cloned when git itself already considers the original unmodified and knows it holds exactly the content the new worktree needs. Anything git is not certain about is left alone.
- Git checks out the rest and writes the index. Git decides what the worktree contains; the clone only decides how the bytes got there.
The two files share disk blocks until one of them changes. Editing either leaves the other untouched, and only the changed blocks start costing space.
Compatibility
You should not be able to tell the difference.
Every item below is checked on every commit, by a suite that performs each operation twice — once through real git worktree add, once through git-sprout — and compares the results. It runs 28 repository fixtures across 41 argument shapes on macOS, Linux (btrfs, XFS, ext4) and Windows (NTFS, ReFS), plus the Linux kernel on two filesystems, and earns its authority by detecting 19 deliberately injected differences and finding none when git is compared against itself.
- Same flags, same stdout, same exit codes. Same stderr too, apart from the progress meter noted below.
- Same hooks, in the same order, with the same arguments.
- Same files, same modes, same index, compared byte for byte against real
git worktree addacross a matrix that includeseolconversion,ident, custom filters, LFS, submodules, sparse checkout, split index, SHA-256 repositories and case-insensitive filesystems, where the correct answer is the same set of already-modified paths git itself leaves behind rather than a clean worktree. - Untracked and ignored files are not copied, exactly as git does not copy them.
- Your repository's configuration is never modified.
- On a filesystem without block cloning, or in a repository that converts files on checkout, it simply runs
git worktree add. - Any flag or combination it does not fully understand is not an error. It hands the whole command to git and exits with git's status.
Two differences you can observe, both deliberate. Files that were cloned keep the timestamp they had in the checkout they came from, rather than the moment the worktree was created. Nothing git does depends on it, but make and anything else that reads modification times can see it.
And on a big repository git worktree add prints a progress meter while it writes the files out. sprout has almost no files left to write, so git never starts one: you see less output because less happened.
Beyond those two, and beyond time and disk, anything you can tell apart is a bug — and this is the suite meant to catch it before you do.
Coding agents and CI
If you run coding agents, you are already paying for this.
Coding agents create an isolated worktree per background session or task. Claude Code shells out to a plain git worktree add and locks the result; the harnesses and worktree managers people build on top do the same, because a worktree is the standard way to give an agent a tree it can break without touching yours.
What a harness runs, verbatim
git -c core.fsmonitor= worktree add --no-track -B <branch> <path> <sha>
That changes the shape of the disk math. One engineer running several agents in parallel on a monorepo allocates a fresh 1.8 GB per agent per task, and those worktrees are created and destroyed all day. On a CI or agent fleet it stops being a laptop annoyance and becomes a provisioning line item.
Because the shim sits in front of git rather than in front of any particular tool, every harness gets this without knowing git-sprout exists: no plugin, no integration, no configuration inside the agent. The parity promise is what makes that safe: anything that intercepts git for an unattended session has to be indistinguishable from git.
Install
One command.
brew install alltuner/tap/git-sprout
Or cargo install git-sprout, or a binary from the releases page.
Usage
git sprout add ../myrepo-feature -b feature # or: git worktree-fast add
Two things have to be true. The filesystem needs block cloning: APFS on macOS; btrfs, XFS with reflinks, or bcachefs on Linux; a ReFS volume or a Windows 11 Dev Drive on Windows. Everywhere else, ext4 and NTFS included, it runs plain git worktree add.
And the repository has to be one that does not convert files on checkout, because a file can only be shared when checking it out would not rewrite its bytes. Git for Windows turns core.autocrlf on by default, and with that setting there is nothing to share, so on a typical Windows repository sprout passes straight through to git worktree add. The same goes for * text=auto eol=crlf on any platform. Repositories with no conversion attributes clone everything, which is the common case on macOS and Linux, the kernel included.
Make it automatic
There is no git setting that can redirect git worktree add.
Both were tested rather than assumed. Git ignores an alias that shadows a builtin, and builtins never go through GIT_EXEC_PATH or PATH. So there are exactly two ways to make every worktree on a machine cheaper, and both are things you install deliberately.
1. A shell function, for what you type yourself
Each block rewrites git worktree add and passes everything else through untouched. It only affects the interactive shell.
bash / zsh — ~/.bashrc, ~/.zshrc
git() {
if [ "${1:-}" = worktree ] && [ "${2:-}" = add ]; then
shift 2
command git sprout add "$@"
else
command git "$@"
fi
}
fish — ~/.config/fish/config.fish
function git
if test (count $argv) -ge 2; and test "$argv[1]" = worktree; and test "$argv[2]" = add
command git sprout add $argv[3..]
else
command git $argv
end
end
PowerShell — $PROFILE
function git {
$real = (Get-Command git -CommandType Application | Select-Object -First 1).Source
if ($args.Count -ge 2 -and $args[0] -eq 'worktree' -and $args[1] -eq 'add') {
$rest = @($args | Select-Object -Skip 2)
& $real sprout add @rest
} else {
& $real @args
}
}
nushell — $nu.config-path
def --wrapped git [...args] {
if ($args | length) >= 2 and $args.0 == "worktree" and $args.1 == "add" {
^git sprout add ...($args | skip 2)
} else {
^git ...$args
}
}
The bash, zsh, fish and nushell blocks were executed against a real git before this page went up. The PowerShell one was reviewed line by line but has not been run on any machine yet, so treat it as unverified and say so if it misbehaves.
Each one matches only worktree add as the first two words. git -C dir worktree add, and anything else a script or an editor runs, goes to git untouched. That is what the shim below is for.
2. A git shim on PATH, for everything else
Editors, worktree managers, CI jobs and agent harnesses spawn git themselves, so a shell function never sees them. The shim is a small git wrapper in its own directory that you put ahead of the real git on PATH; it rewrites worktree add and passes every other command straight through to the real git.
git sprout install-shim # prints the directory it wrote and the PATH line to add
git sprout uninstall-shim # removes it
brew install never does this on its own. A wrapper in front of git is yours to opt into, and one command to undo.
If you already use a worktree manager, this makes it cheaper without changing anything about it: the shim is in front of git, not in front of your tools.