A second checkout,whatever it weighs.

gitto copies the working directory itself, with the filesystem's own clone call: history, submodules, dependencies, build output, the files you never commit. Nothing is duplicated until one side writes, so the copy costs a walk over the directory entries and the blocks you go on to change.

curl -fsSL https://gitto.13e7.co/install | sh
nothing duplicatedboth checkouts point at the same blocks until one of them writes
nothing reinstalleddependencies, build output and local files arrive with the copy
nothing danglinghook paths, worktree registrations and submodule markers are re-addressed

Three agents, three checkouts

Each of them wants a checkout of its own, and a worktree hands it the tracked files and stops there.

git worktree add ../auth-fix -b auth-fix
Preparing worktree
cd ../auth-fix && npm test
vitest: command not found
installing 1,284 packages

The usual ways to live with that:

  1. Keep a pool of checkouts and reset them by hand.
  2. Install and build again in every lane.
  3. Work on one branch at a time.

Discipline? A pool of three drifts into twenty-seven, and the slot labelled main turns out to be three weeks behind. Copying was never the expensive part. APFS and btrfs have shared blocks on write for a decade, and git has never asked them for it.

The canonical checkout is the one nobody works in. Every lane is a copy of it that starts finished, and the two share their storage until one of them writes.

Nothing to rebuild

The whole directory comes along, and the filesystem shares its blocks until one side writes. What a worktree leaves you to rebuild is already there:

with git worktree

package.json
src

with gitto

package.json
src
node_modules
vendor
build
settings.local.json
gitto new auth-fix
cloning storefront -> storefront-auth-fix by clonefile
  repointed core.hooksPath at this clone's own hooks
  branch auth-fix on origin/main, 4 submodules
/Users/you/work/storefront-auth-fix

Measured on a 13 GB checkout with four submodules: 21 seconds, and 60 MB of disk that was not shared. A repository twice the size copies in about the same time, because what is walked is the directory entries rather than the bytes.

Every clone is a real repository

Not a worktree, so it holds its own history and its own branch, and two of them never share an index. The canonical checkout is the one nobody works in.

gitto list
canonical storefront  main
storefront-auth-fix      auth-fix               dirty=0     unpushed=0   idle=12m   new=60 MB
storefront-search        feat/search-ranking    dirty=3     unpushed=2   idle=6d    new=210 MB

A clone starts on origin/HEAD unless you name another base. Passing HEAD gives you the canonical exactly as it stands, uncommitted work included, which is how you hand an agent the mess you are in.

What a copy breaks

Copying the files is one line. The work is that a checkout is full of references to where it lives, and a plain copy leaves every one of them pointing at the original: hook paths, worktree registrations at every submodule depth, symlinks into the directory you copied from.

gitto doctor auth-fix
storefront-auth-fix
  nothing points at the canonical

gitto re-addresses what it can and drops what cannot survive the move, such as a worktree the canonical keeps inside itself, whose history stays behind. What it cannot decide it reports instead of rewriting:

gitto doctor search
storefront-search
  still pointing outside this clone:
    symlink  .agents -> /Users/you/work/storefront/.agents
    hosts    storefront-docs

doctor knows what git knows. A reference from outside git, an editor workspace or a line in ~/.ssh/config, is not on that list, so a clean report means nothing points at the canonical. It does not mean the directory is safe to delete.

Ending a lane without losing it

A clone holding unpushed commits, uncommitted changes, or the history of a worktree living somewhere else is not removed. Both counts read the submodules, where a commit nobody pushed leaves the top level looking clean:

gitto remove auth-fix
gitto: auth-fix holds 1 commits no remote has, in it or in a submodule.
      push them, or keep them with 'gitto remove auth-fix --archive'.

--archive takes it anyway. The checkout and every submodule are bundled beside the canonical, work that was never committed is committed into the bundle, and every bundle is read back before anything is deleted. prune --stale 7 does the same for the lanes an agent walked away from.

gitto remove spike-oauth --archive
removed storefront-spike-oauth, and what it held is in
  /Users/you/work/storefront.gitto-archive/spike-oauth-20260925-104233

Several at once

Copying reads the canonical and sync writes to it, so both announce themselves in a lock the canonical carries. Any number of clones can be taken at the same time, and one taken during a sync waits for it rather than copying a tree that is moving.

gitto new auth-fix
waiting for gitto sync in storefront
cloning storefront -> storefront-auth-fix by clonefile

How it compares

Running several agents at once made a second checkout into a category, and most of it is built on git worktree. What a worktree gives you is a shared object store, which a shared-block copy hands over for free.

git clonehistory over the network, tracked files, nothing else
git worktreetracked files; submodules uninitialised, ignored files gone, branches and the stash shared with every other worktree
worktree managersa worktree, and a declared step that copies the ignored directories back in
gittothe directory itself, submodules at every depth, re-addressed and independent from the first write

The rest of that table, including the other whole-tree copies and what each one does about a directory that still remembers where it lived, is in the comparison.

Install

One POSIX shell script, no runtime. It goes in ~/.local/bin, and it needs nothing but git and a filesystem that can share blocks.

curl -fsSL https://gitto.13e7.co/install | sh

APFS on macOS, which is every Mac since 2017. On Linux, btrfs, XFS created with reflink=1, or OpenZFS 2.2 and later. Not ext4, which cannot share blocks at all.

Plugin

The plugin adds the skill, which is what makes an agent reach for a clone when the work wants its own checkout. It also carries the reasoning behind each refusal, so a blocked command is read and answered.

claude plugin marketplace add eastriverlee/gitto
claude plugin install gitto@13e7

The package follows the Agent Plugins layout around an Agent Skills skill, and .agents/skills is the directory its clients share.

Give the next branch a checkout that starts finished

curl -fsSL https://gitto.13e7.co/install | sh