A clone of your working directory, not of the repository.

git worktree copies tracked files;not the hours you spent building.

Three agents on three branches means three checkouts. A worktree hands each one the tracked files and stops there, so every lane resolves its dependencies and runs its build again before any work starts.

  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.

A pool drifts: a slot's branch changes and its state does not, and the directory name stops saying what it holds. Building again is minutes per lane, forever. Working serially is the thing you were trying to stop doing.

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 attendance-fix
cloning internkim -> internkim-attendance-fix by clonefile
  repointed core.hooksPath at this clone's own hooks
  branch attendance-fix on origin/main, 4 submodules
/Users/you/work/internkim-attendance-fix

That copy carried 13 GB in 21 seconds and cost 60 MB of disk. Dependencies, build output, submodules at every depth and untracked local files are all present, so there is nothing to run before work starts.

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 instead of adding one more worktree to a pile nobody is counting. It also carries the reasoning behind each refusal, so a blocked command is read rather than worked around.

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

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

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 internkim  main
internkim-attendance-fix attendance-fix         dirty=0     unpushed=0
internkim-jev-router     feat/jev-router        dirty=3     unpushed=2

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 attendance-fix
internkim-attendance-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 jev-router
internkim-jev-router
  still pointing outside this clone:
    symlink  .agents -> /Users/you/work/internkim/.agents
    hosts    internkim-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, never that a directory is safe to delete.

Removing a clone

A clone that holds unpushed commits, uncommitted changes, or the history of a worktree living somewhere else is not removed. The refusal names what would be orphaned.

gitto remove jev-router
gitto: jev-router hosts the history of worktrees that live outside it:
        /Users/you/work/internkim-docs
      removing it would leave each of them without a repository.

The same care applies before anything is copied. gitto measures the filesystem first, so a machine that cannot share blocks is told so rather than quietly paying full price:

gitto new attendance-fix
gitto: copying here costs the full size, so a clone would too.
      macOS needs APFS; Linux needs btrfs, XFS with reflink=1, or OpenZFS 2.2+.
      ext4 and tmpfs cannot share blocks at all.