A repository (repo) is a project's files plus their whole history in git. A commit is one saved step in that history.
A branch is a separate line of commits inside the repo. You always make a new branch from an existing one, usually the default branch. On GitHub the default branch is called main unless you rename it.
On your branch you can change anything without touching main or anyone else's work. When the work is ready, it goes back into main through a pull request. A branch made for one feature is often called a feature branch or topic branch.
In Matt's Flows, each Ticket gets its own branch. That keeps one Ticket's half-done code away from the others, and makes it clear which commits belong to which Ticket.
Worktrees
Normally a repo folder has one branch checked out at a time. Switching branches swaps the files in that folder.
A worktree is a folder with one of the repo's branches checked out. A repo can have several worktrees, each on a different branch. They all share one history, so a commit made in one worktree is visible from the others. This lets you work on more than one branch at a time.
The folder you cloned is the main worktree. A repo has exactly one.
Each extra folder, made with git worktree add, is a linked worktree.
By default, a branch can be checked out in only one worktree at a time. Git refuses to check it out a second time unless you force it with --force.
When you're done, remove the folder with git worktree remove.
main
a feature brancha linked worktree
a different brancha linked worktree
(commit counts are illustrative)
They all share one history
Why agents use them
Two agents working in one folder would trip over each other's files. Give each its own worktree and branch, and they can build different Tickets side by side.
That's exactly what implement-spec does: it runs one fresh helper agent per Ticket, each in its own worktree on its own branch, and then merges each branch into one shared branch for the whole Spec.
Going deeper
4 min read · Going deeper not read
Why it exists
Matt's implement page (it is labelled updated 2026-08-24) warns that running several of its sessions side by side in one checkout "is worse than unsupported". His reason fits in one line: "The sessions share one working directory, one index, and one HEAD."
In Git's own glossary, HEAD is "the current branch", and the index is "a stored version of your working tree".
His v1.3 notes (2026-10-05) announced implement-spec, the Skill described above.
How it works underneath
Git gives each linked worktree a private folder inside the main repo's .git/worktrees/. The linked folder holds a .git file that points back there.
Here is what's shared, and what each worktree keeps for itself:
Shared: the history, nearly every ref under refs/, and the config file. A ref is "a name that points to" something git stores, such as a commit. Branches live under refs/heads/, and the stash lives at refs/stash.
Kept apart: its files, its HEAD and its index.
Git's own docs give the rule: "all refs starting with are shared". Only three kinds are not: , and .
Citations (57)
From snapshot/docs/docs.github.com/branches.md, line 11: “You always create a branch from an existing branch. Typically, you might create a new branch from the default branch of your repository. You can then work on this new branch in isolation from changes that other people are making to the repository.”
what's shared, and what each worktree keeps for itself
Claude Code builds on this. claude --worktree feature-auth makes a worktree under .claude/worktrees/feature-auth/, on a new branch named worktree-feature-auth. Its docs say to add .claude/worktrees/ to your .gitignore, so those folders don't show up as untracked files in your main checkout.
A real example
On 2026-07-02, a user opened issue #429 on Matt's repo. They had been running several /implement sessions at once in one checkout, one per issue. In a single afternoon:
one session's git commit --amend landed on the other session's commit;
a stash "silently disappeared";
commits landed on the wrong branch, because HEAD had moved under a session.
Their verdict: "None of these were reasoning mistakes." The fix they asked for was a worktree per session: "separate working directory, separate index, separate HEAD".
Three days later, another user replied that worktrees fix only two of the three. The amend and the wrong branch go away. The vanished stash doesn't, because "refs/stash is a single shared ref across every worktree". Matt's implement page now says the same: "worktrees alone do not fix the stash case". The issue was closed on 2026-10-06.
That reply's advice: in a repo where agents work side by side, don't use git stash to set work aside; commit it on your own branch instead.
Where it goes wrong
Collisions wait for the merge. In his v1.3 notes Matt calls this a rough edge: "worktrees do not remove collisions, they move them to merge time". Each helper agent sees only its own Ticket. His implement-spec page tells of one user whose two Tickets added the same string under two names, blockedSince and blockedOn. Git kept the files apart, so nothing clashed until the branches met. His fix: when two Tickets touch one shared file, add a blocked-by link so they run one after the other, or have the exploration notes fix the exact names each Ticket adds.
A new worktree is missing files. "A worktree holds only what git tracks." Tests that read gitignored fixtures, local databases or credentials "can silently skip there", so a Ticket can report green without its key test running. Claude Code's docs agree that untracked files like .env "are not present" in a new worktree. Its answer is a .worktreeinclude file at the repo root, written like a .gitignore, listing the gitignored files to copy in. Matt's answer for a Ticket that needs untracked material is to run its check in the main checkout instead.
Try it
In your practice project (set it up first with keeping-track's Try it step if you haven't), see the sharing for yourself, from the repo root:
The stash you made in yoga-try-a, holding the new try.txt, shows up in yoga-try-b's list. If your project has a gitignored file, such as a .env, look for it in ../yoga-try-a: it isn't there. Clean up with git -C ../yoga-try-a stash drop, then git worktree remove ../yoga-try-a and git worktree remove ../yoga-try-b, then git branch -d try-a try-b.
Going deeper's Check questions are asked in Next up.
“If <branch> does exist, it will be checked out in the new worktree, if it’s not checked out anywhere else, otherwise the command will refuse to create the worktree (unless --force is used).”
From snapshot/docs/git-scm.com/git-worktree.md, lines 311–315: “In general, all pseudo refs are per-worktree and all refs starting with refs/ are shared. Pseudo refs are ones like HEAD which are directly under $GIT_DIR instead of inside $GIT_DIR/refs. There are exceptions, however: refs inside refs/bisect, refs/worktree and refs/rewritten are not shared.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 143: “Each implementer sees only its own ticket and the shared notes, never the other's work in progress, so one user's web and mobile tickets added the same string as blockedSince and blockedOn.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 143: “When two frontier tickets touch one shared file, either add a blocking edge between them so they run one after the other, or have the exploration notes fix the exact names each ticket adds.”
From snapshot/web/code.claude.com/docs-en-worktrees.md, line 166: “A worktree is a fresh checkout, so untracked files like .env or .env.local from your main repository are not present. To copy them automatically when Claude creates a worktree, add a .worktreeinclude file to your project root.The file uses .gitignore syntax. Only files that match a pattern and are also gitignored are copied”