4.9 KiB
Worktree Workflow
The day-to-day "how do I move fast without stepping on myself" guide. For the branching/release contract (when to merge, when to tag), see RELEASE.md "Branching policy" and
docs/decisions.md§23. This doc is only about worktrees — the parallel-folder layer that sits underneath that contract.
The one-paragraph mental model
A git worktree is a second working folder backed by the same .git. It's a
full checkout on its own branch that shares the object store and refs with your
main checkout — no clone, no re-download, instant. You alt-tab between folders
instead of running git checkout back and forth. That matters because switching
branches in one folder invalidates the Gradle build cache and forces the IDE to
re-index every time; separate worktrees keep each branch's caches warm in
parallel. This is the entire reason per-feature worktrees feel fast.
main ──●──────────────────●───────── released only; tags cut HERE
\ /
dev ──●──●──●──●──●──●──●─────────── integration; [Unreleased] accumulates
/ / /
feat/a ──● worktree A ┐
feat/b ────● worktree B ├─ one worktree = one branch = one unit of work
feat/c ──────● worktree C ┘
Four rules cover everything
- One worktree = one branch = one feature/fix, in its own folder.
- Branch off
dev, PR back todev. CI green → merge--no-ff. mainonly receivesdev→mainrelease merges. Tag frommain.- Worktrees are disposable — remove them once the PR merges.
In Orca (the normal path here)
This repo is developed inside Orca, which has its own worktree manager. Let Orca
create and tear down the per-feature worktree — that's how features ship in
parallel without index contention. Use the orca-cli skill / Orca worktree
commands rather than raw git worktree, so Orca tracks the worktree's state and
comment. Your job is just to keep each worktree to one unit of work and follow
the four rules above; gitflow is the merge discipline layered on top.
Why this matters for agents specifically: multiple Claude/agent sessions sharing a single checkout collide on the git index (the "shared worktree, concurrent sessions" failure mode — pathspec-commit workarounds, half-staged trees). One worktree per session removes the collision entirely. If you ever do run two sessions in one folder, commit with explicit pathspecs (
git commit -- <paths>) and checkgit statusbefore every commit.
Raw git worktree (fallback, outside Orca)
When you're not driving through Orca:
# Create a worktree for a new feature branch off dev
git worktree add ../hermes-feat-bridge-scroll -b feature/bridge-scroll dev
# ...work in that folder, commit, push, open a PR into dev...
# After the PR merges, remove the worktree and prune the branch
git worktree remove ../hermes-feat-bridge-scroll
git worktree prune
Useful checks:
git worktree list # every worktree + its branch + HEAD
git worktree remove <path> # delete a worktree (must be clean, or pass --force)
Gotchas
- A branch can be checked out in only one worktree at a time. Trying to check
out
devin two worktrees errors — that's intentional. Keepdev/mainin the main checkout and feature branches in their own worktrees. - Worktrees share the same
.git, so agit fetch/git gcin any worktree affects all of them. Refs and stashes are shared; the working tree and per-worktreeHEADare not. - Don't nest a worktree inside the repo — put it in a sibling dir
(
../hermes-feat-x), not under the repo root, or it gets swept into globs and IDE indexing. - Build outputs are per-folder. That's the point (warm caches), but it also
means three worktrees ≈ three
build/trees on disk. Gradle's local build cache is shared through the Gradle user home and can reuse compatible task outputs across worktrees. Prune merged worktrees so build trees don't accumulate. - Serialize heavy Gradle invocations on one host. Worktrees isolate source and output directories, but concurrent Android compiles, lint, tests, and APK packaging still compete for the same CPU, memory, daemon pool, and local cache. Keep one heavy Gradle lane active at a time; parallelism inside that invocation remains enabled.
How this maps to releasing
Worktrees change nothing about the release contract. Feature worktrees merge to
dev; releases are still cut by merging dev → main with --no-ff and tagging
from main (Android android-v*, server server-v*, desktop desktop-v*). Version bumps
happen on dev at release-prep, never on a feature branch — see RELEASE.md.