Comparison
Worktree managers, whole-tree CoW clones, and what each one leaves you holding.
Running several agents at once turned "a second checkout" into a category, and
most of it is built on git worktree. The table is what a new checkout arrives
holding.
| history | submodules | ignored files, dependencies, build output | branch namespace and stash | |
|---|---|---|---|---|
git clone | copied over the network | cloned again on request | gone | its own |
git worktree | shared | arrive uninitialised | gone | shared with every other worktree |
| worktree managers | shared | uninitialised, unless the tool adds a step | a configured copy step, reflinked where it can be | shared |
| whole-tree CoW clones | copied by the filesystem | copied, handling varies | carried, often as symlinks | its own |
gitto | copied by the filesystem | copied, at every depth, and re-addressed | carried, as clones of the blocks | its own |
worktrunk, Conductor,
ccmanager and Claude Code's own isolation: worktree are worktree managers: they
address worktrees by branch name, give each agent a session, and inherit what a
worktree is. worktrunk reflinks the ignored directories through a
copy-ignored step, which is the same filesystem call gitto makes, applied to
the part of the checkout git was told to ignore.
cow is the nearest thing to gitto: whole-tree
clonefile on APFS, .git and ignored files included, with create, list,
remove, sync and gc.
What is left after the copy
Copying is the part everything here agrees on. What separates them is what they do about a directory that still remembers where it used to live.
gitto | worktree managers | whole-tree CoW clones | |
|---|---|---|---|
core.hooksPath, inherited worktree registrations, submodule gitdir markers | re-addressed, at every submodule depth | not applicable, the worktree is registered | varies |
| dependencies in the new checkout | clones of the blocks, independent from the first write | copied or reflinked by a declared step | often symlinked into the source, and made independent on request |
| a filesystem that cannot share blocks | refused, after measuring a 32 MB probe | copies in full | warns and copies in full |
| removing a checkout that still holds work | refused, or archived to a verified bundle | git worktree remove refuses a dirty tree | prompts, and --force overrides |
| work committed inside a submodule and pushed nowhere | counted, and it stops the removal | not counted | not counted |
| two runs touching the source at once | a lock the source carries | none | none |
| a checkout that already exists | gitto adopt converts a worktree in place | it is already a worktree | not applicable |
A symlinked dependency directory is the difference worth naming. It makes the
new checkout cheap in the same way a clone of the blocks does, and it leaves two
checkouts writing into one directory. A process that resolves the path it is
given, a container mount, or anything that reads through /proc will see the
source's path rather than the lane's.
What it does not try to be
gitto makes checkouts. It has no session manager, no diff viewer, no pull
request flow, and no opinion about which agent runs where. A worktree manager
that wants cheaper checkouts can call it in place of git worktree add.
It also refuses to run where the filesystem cannot share blocks, which is ext4 and tmpfs, and ext4 is the installer default on Ubuntu and Debian. A worktree manager works there. This does not.
Measuring the filesystem
Before any of that, `gitto` writes a 32 MB probe file, clones it with the system call, and compares free space before and after. A copy that consumed the probe's own size was a full copy, whatever the exit status said.
Q&A
Short answers to what people ask before they install it.