Git Worktrees
How grepai sets up linked git worktrees automatically by copying the main worktree's config and indexes, and how each backend handles them.
Git Worktree Support
grepai detects git worktrees. When you work in a linked worktree (created with git worktree add), it sets up the worktree from the main worktree’s .grepai/ automatically, so you do not need to run grepai init again.
Quick Start
# The main worktree is already set up and indexed
cd /path/to/my-project
grepai watch
# Create a linked worktree for a feature branch
git worktree add ../my-project-feature feature-branch
# Use grepai there right away
cd ../my-project-feature
grepai search "authentication flow" # GOB: uses the copied index
grepai trace callers "HandleRequest" # uses the copied symbol index
With the default GOB backend, search and trace work immediately from the copied indexes. With PostgreSQL or Qdrant, see Backend Behavior.
How It Works
When a grepai command that looks up the project (such as search, trace, refs, rpg, status or watch) runs inside a linked worktree that has no .grepai/config.yaml, grepai:
- Detects the linked worktree with
git rev-parse(sogitmust be installed). - Checks that the main worktree has a
.grepai/config.yaml. If not, nothing happens. - Copies
index.gob,symbols.gob, thenconfig.yamlfrom the main worktree into the linked worktree’s.grepai/. - Adds
.grepai/to the linked worktree’s.gitignore(creating the file if needed).
A running grepai watch in the main worktree does the same for every linked worktree it discovers (see Disabling Worktree Discovery).
The copy is safe against concurrent runs. grepai holds the linked worktree’s .grepai/writer.lock for the whole copy (waiting up to 5 seconds for it). Each file is written to a synced temporary file, then moved into place atomically. config.yaml is copied last and serves as the completion marker: a .grepai/ with only writer.lock or partial files is not considered initialized, and a watcher never loads a half-copied seed. If any step fails, the files from that attempt are removed and a later run retries.
What Gets Copied
| File | Purpose | Required |
|---|---|---|
config.yaml | Embedder and store configuration | Yes: auto-init stops if it is missing or invalid |
index.gob | Vector index (GOB backend) | No: skipped if absent |
symbols.gob | Symbol index for trace and refs | No: skipped if absent |
The RPG graph (rpg.gob) is not copied. If RPG is enabled, it is built the first time grepai watch or grepai index indexes the worktree.
Backend Behavior
Each worktree gets its own .grepai/ and its own index scope:
| Backend | Behavior |
|---|---|
| GOB | The copied index.gob is the worktree’s starting index. Each worktree then keeps an independent index: changes in one do not affect the other. |
| PostgreSQL | The config is inherited. Data is stored under the worktree’s own project ID (its absolute root path), so the worktree starts with no vectors: search returns nothing until a watcher has indexed it. Nothing is shared with the main worktree. |
| Qdrant | Same as PostgreSQL: the default collection name is derived from the worktree’s root path, so the worktree starts empty. |
Note: if the main config sets
store.qdrant.collectionexplicitly, linked worktrees inherit that exact name and write into the same collection as the main worktree. Leave the key empty to keep worktrees separate.
The copied symbols.gob works with every backend, so trace and refs answer immediately in all cases.
Running grepai watch in a Worktree
cd /path/to/my-worktree
grepai watch
The watcher starts from the copied state and updates the worktree’s index. With GOB, files whose content matches the copied index are skipped. With PostgreSQL or Qdrant, this first run indexes the worktree from scratch.
You often do not need this: a grepai watch running in the main worktree already watches linked worktrees, unless discovery is disabled.
Note: the background watcher’s PID and log files are named after the repository’s worktree ID (
grepai-worktree-<id>.pidand.log), which is shared by all worktrees of a repository. If a background watcher is already running for the repository,grepai watchin a linked worktree stops withwatcher is already running in background.
Worktree Identification
A repository is identified by a stable worktree ID: the first 12 hex characters of the SHA-256 hash of the git common directory. The main worktree and all its linked worktrees share the same ID. grepai uses it to name the background watcher files and shows it in grepai init and grepai watch --status.
Git worktree detected.
Main worktree: /path/to/main-repo
Worktree ID: 0adda787cae4
Backend: gob
Explicit Initialization with --inherit
To create the worktree’s config yourself (for example to edit it before the first index), run grepai init in the linked worktree before any other grepai command (otherwise auto-init has already created .grepai/config.yaml, and init reports that grepai is already initialized):
cd /path/to/my-worktree
grepai init --inherit
grepai init prints the detection block shown above, then:
- With
--inherit, it copies the main worktree’s configuration without asking. - Without
--inherit, it asksInherit configuration from main worktree? [Y/n]. - With
--yesbut without--inherit, it does not inherit and writes a default configuration instead.
init --inherit writes config.yaml only. It does not copy index.gob or symbols.gob, so run grepai watch (or grepai index) afterwards to build the worktree’s indexes.
For a fully non-interactive setup:
grepai init --inherit --yes
Disabling Worktree Discovery
By default, grepai watch in the main worktree lists linked worktrees (git worktree list), auto-initializes them, and watches them alongside the main project. With many short-lived worktrees (for example AI agent sessions), this multiplies indexing work and memory. To opt out, set this in the main worktree’s .grepai/config.yaml:
watch:
discover_worktrees: false
The watcher re-reads this key on every discovery pass (every 3 seconds), so no restart is needed: worktrees already watched are released on the next pass. The key is only read from the main worktree’s config; setting it in a linked worktree’s copy has no effect. If the config cannot be parsed, discovery skips that pass and logs a warning.
This only affects discovery by the main watcher. Running a grepai command inside a linked worktree still auto-initializes it.
Troubleshooting
| Problem | Solution |
|---|---|
| Auto-init does not trigger | Check that the main worktree has a valid .grepai/config.yaml (run grepai init there first) and that git is installed. For discovery by the main watcher, also check that watch.discover_worktrees is not false. |
no grepai project found (run 'grepai init' first) in a worktree | The main worktree is not initialized, or the directory is not a git worktree. Run grepai init in the main worktree. |
| Search returns nothing (PostgreSQL or Qdrant) | The worktree has its own empty scope. Run grepai watch in the worktree, or keep a watcher running in the main worktree with discovery enabled. |
| Search returns stale results (GOB) | Run grepai watch in the linked worktree to index its changes. |
watcher is already running in background | A background watcher already runs for this repository. Check it with grepai watch --status, or stop it with grepai watch --stop. |
| Too many worktrees indexed or high memory | Set watch.discover_worktrees: false in the main worktree’s config, or prune old worktrees with git worktree remove and git worktree prune. |