Skip to content

Git Worktree Architecture

Sidequest uses git worktrees to let you run multiple Claude Code sessions against the same repository in parallel — each on its own branch, with its own working directory, without any stashing or switching.

A git worktree is a linked copy of your repository that shares the same .git object store but has its own working tree and checked-out branch. Unlike cloning, worktrees share history, refs, and objects with the original repo. This means they are created instantly and use almost no extra disk space.

# Standard git: one repo, one branch at a time
~/my-project (main)
# With worktrees: one repo, multiple branches simultaneously
~/my-project (main) # your original repo
~/.sidequest/worktrees/<quest-id> (feat/auth) # worktree for quest A
~/.sidequest/worktrees/<quest-id> (fix/bug) # worktree for quest B

Without worktrees, running parallel branches requires either cloning the repo multiple times (slow, wastes disk) or constantly stashing and switching branches (error-prone, blocks other work). Worktrees solve both problems:

  • True isolation. Each quest gets its own directory. Claude Code sessions cannot interfere with each other.
  • No stashing. Your main branch stays untouched. Uncommitted work in one quest does not affect another.
  • Shared git history. All worktrees share the same object database. Fetches and commits in one are visible from another.
  • Fast creation. Creating a worktree takes milliseconds since it only needs to check out files, not copy the entire repo.

All worktrees live under a centralized directory in your home folder:

~/.sidequest/
worktrees/
<quest-id>/ # One directory per Changes quest
.git # File (not directory) pointing to parent repo
src/ # Full working tree for this branch
...
multirepo/
<quest-id>/ # Multi-repo quests group child worktrees
frontend/ # Worktree for frontend repo
backend/ # Worktree for backend repo
...

Each quest is identified by a UUID. The worktree path is deterministic: ~/.sidequest/worktrees/<quest-id>. This makes cleanup reliable — Sidequest can always find and remove a quest’s worktree by ID.

When you create a Changes quest, Sidequest generates a branch name using Claude. The prompt and quest title are sent to Claude Code, which returns a conventional branch name like feat/add-user-auth or fix/login-validation.

The branch name is sanitized to be a valid git ref:

  • Lowercased, whitespace replaced with hyphens
  • Only alphanumeric characters, hyphens, dots, and slashes are kept
  • Consecutive dots/hyphens collapsed, trailing dots and .lock removed
  • Truncated to 60 characters

If Claude is unavailable, Sidequest falls back to a random three-word name from the system dictionary (e.g., maple-frost-ocean).

A temporary branch quest/<first-8-chars-of-id> is created immediately so the worktree can be set up without waiting for the Claude API call. Once the real branch name is generated, the branch is renamed in place.

When a Changes quest is activated:

graph TD
A[Quest activated] --> B[Compute worktree path]
B --> C{Directory exists?}
C -->|Yes| I[Reuse existing worktree]
C -->|No| D{Branch exists?}
D -->|Yes, has unique commits| E[Create worktree from branch]
D -->|Yes, stale| F[Delete branch, recreate from base]
D -->|No| G[Create new branch from base]
E --> H[Configure upstream tracking]
F --> H
G --> H
I --> H
  1. Sidequest computes the worktree path: ~/.sidequest/worktrees/<quest-id>
  2. If the directory already exists, it is reused as-is
  3. If the branch already exists with unique commits, the worktree is created from that branch
  4. If the branch exists but has no unique work (stale), it is deleted and recreated from the base branch
  5. Otherwise, a new branch is created from the base branch (or HEAD if no base is specified)
  6. Upstream tracking is configured so gh pr create targets the correct base branch
git worktree add -b feat/my-feature ~/.sidequest/worktrees/<quest-id> main

Claude Code runs inside the worktree directory. All file changes, commits, and git operations happen within this isolated working tree. You can view diffs, stage files, and create pull requests from Sidequest’s UI.

The worktree shares refs with the parent repo, so remote branches fetched in one worktree are available in all of them.

When a quest is deleted, Sidequest cleans up in this order:

  1. Kills the tmux session (if running) and waits for it to fully terminate
  2. Runs git worktree remove --force from the parent repo
  3. Falls back to deleting the directory directly if the git command fails
  4. Prunes stale worktree references with git worktree prune

When a Changes quest is complete and you want to merge the work back:

  • Create a PR. Use the built-in PR creation flow or Claude to push the branch and open a pull request against the base branch.
  • Squash merge. Sidequest supports squash merging the quest branch back into the target branch. This collapses all commits from the quest into a single commit on the target, keeping your main branch history clean.

Under the hood, a squash merge runs:

git checkout main
git merge --squash feat/my-feature
git commit -m "Squashed merge of feat/my-feature"

After merging, delete the quest from Sidequest to clean up the worktree and branch.

Research quests do not create worktrees or branches. They run Claude Code directly in the project’s root directory. This is appropriate for read-only exploration, code analysis, and question-answering tasks that do not need branch isolation.

Git prevents two worktrees from having the same branch checked out. If you see this error, another worktree (or your main repo) already has that branch active. Delete the conflicting quest or switch the main repo to a different branch.

If Sidequest is force-quit, worktree directories may be left behind. You can view and clean up orphaned worktrees from Settings, or remove them manually:

Terminal window
ls ~/.sidequest/worktrees/
rm -rf ~/.sidequest/worktrees/<quest-id>
cd ~/your-repo && git worktree prune

Because worktrees share the git object store, git fetch in one location updates refs everywhere. This is a feature, not a bug — it means your quest worktrees always have access to the latest remote state.