Files
tty7/docs/git/worktrees.mdx
T
l0ng-ai 8cf31c718d feat(worktree): setup, .worktreeinclude, agent launch, recoverable removal, and a worktree CLI (#1009)
* feat(worktree): setup script, .worktreeinclude, fresh base, recoverable removal

- Start new worktrees from the remote default branch, fetched first, with
  --no-track; fall back to the current branch without a remote.
- Carry gitignored files listed in .worktreeinclude over from the main
  checkout, copy-on-write (clonefile on macOS, copy_file_range elsewhere);
  remote hosts copy through the Host trait under a size budget.
- Run .tty7/setup in the first pane before the agent, with TTY7_ROOT_PATH,
  TTY7_WORKTREE_PATH, TTY7_WORKTREE_NAME and a per-worktree TTY7_PORT block.
  The script only runs once its exact content is approved for the repo.
- The New Worktree dialog picks what the first pane starts (Shell or a
  recent agent) and takes a task for agents that open on a first message.
- Removal snapshots the checkout, uncommitted work included, under
  refs/tty7/trash/<name> first; the ref also retires the name. A branch
  git refuses to delete is reported instead of silently kept.
- Hide .tty7/worktrees via info/exclude rather than a catch-all
  .tty7/.gitignore, so .tty7/setup can be committed.

* feat(cli): tty7 worktree new/ls/rm

- worktree new: the GUI dialog's worktree from the command line — create,
  carry .worktreeinclude, open a tab named after the branch, and type
  .tty7/setup && <agent> [task] into it. Prints the path first.
- worktree ls: every checkout of the repo, tty7's marked, with the live
  panes working in each.
- worktree rm: refuses while panes are inside unless --close-panes, and a
  dirty checkout unless --force; reports the snapshot ref and a kept branch.
- Move shell_quote and the first-line builders into tty7-core so the GUI
  and the CLI type the same line.
- Docs: CLI reference and the Worktrees page cover .worktreeinclude,
  .tty7/setup, TTY7_PORT and recoverable removal.

* fix(worktree): run setup and the agent inside the worktree; Start is a dropdown

- The first line now opens with cd into the worktree: a shell's startup
  files can move the pane, and setup then ran in (and wrote into) the main
  checkout.
- The Start choice is a dropdown listing Shell and every agent this machine
  offers, instead of a segmented switch capped at three.
2026-09-29 16:54:59 +08:00

133 lines
4.6 KiB
Plaintext

---
title: "Worktrees"
description: "One checkout per task: fresh branch, set up, and handed to an agent — in one dialog."
---
Running two agents on the same repository at once means they fight over the
working tree. A git worktree is the fix, and tty7 makes it a single dialog:
create the checkout, make it runnable, and start the agent in it.
## Creating one
**New Worktree Tab…** — in Search Everywhere, the tab's right-click menu, and
the application menu — asks:
| Field | Default |
|---|---|
| **Worktree Name** | A fresh name that no branch, directory or removed worktree has used |
| **New Branch** | The same name, editable |
| **Start From** | The remote's default branch (`origin/main`), fetched first; the current branch when there is no remote |
| **Start** | A dropdown: Shell, or any agent on this machine — the last one used is picked |
| **Task** | The agent's first message (Claude Code, Codex and Gemini take one) |
Each field opens on a suggestion you can accept or type straight over.
<Frame caption="The New Worktree Tab dialog, every field pre-filled">
<img src="/images/new-worktree.webp" alt="Creating a worktree" />
</Frame>
Confirm and tty7 creates the worktree, copies in what `.worktreeinclude` asks
for, opens a tab there, and runs `.tty7/setup` followed by the agent. The
[sidebar](/window/sidebar) files it under the same repository group as its
parent, on its own branch.
The new branch does not track `origin/main`: its first `git push -u` goes to a
branch of its own name.
## Files a checkout needs: `.worktreeinclude`
A fresh checkout has none of your gitignored files — no `.env`, no local
settings. List the ones it needs in `.worktreeinclude` at the repository root,
in gitignore syntax:
```
.env
.env.local
config/local/*.json
```
A path is copied only if it matches **and** git ignores it.
Copies are copy-on-write where the filesystem supports it (APFS on macOS,
btrfs and XFS on Linux): a copied directory costs no disk until one side
changes it. Nothing is symlinked, because two checkouts sharing one dependency
tree break each other the moment their lockfiles disagree. On a remote machine
the files go over the connection, up to 64 MB in total — enough for
configuration, not for `node_modules`.
## Making it runnable: `.tty7/setup`
Commit an executable at `.tty7/setup` — any language, with a shebang — and
every new worktree runs it in its first tab, before the agent. Install
dependencies there, rather than copying them:
```sh
#!/bin/sh
set -e
pnpm install
echo "PORT=$TTY7_PORT" > .env.local
```
| Variable | Value |
|---|---|
| `TTY7_ROOT_PATH` | The main checkout |
| `TTY7_WORKTREE_PATH` | The new worktree |
| `TTY7_WORKTREE_NAME` | Its directory name |
| `TTY7_PORT` | The first of ten ports this worktree has to itself |
`TTY7_PORT` comes from the worktree's path, so a dev server started there does
not collide with its siblings, and the same worktree always gets the same
ports. The setup and the agent are chained with `&&`: if setup fails, the
agent does not start and the error stays on screen.
The script is code from the repository, so tty7 asks before running it the
first time, and again whenever its content changes. Without a setup script,
the dialog suggests one based on your lockfile (`pnpm install`, `uv sync`, …).
Setup runs on macOS and Linux; Windows worktrees skip it.
## Where they go
Worktrees land inside the repository, under:
```
<repo>/.tty7/worktrees/<name>
```
The directory is listed in `.git/info/exclude`, so it never shows up in
`git status`, and `.tty7/setup` next to it stays committable.
## Removing one
Closing a worktree tab offers to remove the worktree with it:
- **Clean tree** — *Remove Worktree* or *Keep*.
- **Dirty tree** — the dialog says so, and removing requires the explicit
*Discard Changes & Remove*.
Before anything is deleted, the checkout's state — uncommitted and untracked
files included — is saved under `refs/tty7/trash/<name>`. Even a discarded
change can come back:
```bash
git checkout refs/tty7/trash/<name> -- .
```
The branch is deleted only if it is merged; otherwise tty7 says it kept it.
*Keep* leaves the worktree on disk, and `tty7 worktree ls` finds it later.
## From the command line
```bash
tty7 worktree new --agent claude --task "fix the flaky login test"
tty7 worktree ls
tty7 worktree rm quiet-otter
```
See the [CLI reference](/cli/reference#worktree--one-checkout-per-task).
<Tip>
Pair this with [agent sessions](/agents/sessions): a worktree per agent means
two Claude Codes can work on the same repository without stepping on each
other's files.
</Tip>