name: using-git-worktrees
description: Creates isolated git worktrees in XDG data directory for parallel development. USE WHEN starting feature work that needs isolation from current workspace OR before executing implementation plans OR working on multiple branches simultaneously OR need clean test environment. Creates worktrees in ~/.local/share/worktrees///.
UsingGitWorktrees
Create isolated git workspaces for parallel development using XDG data directory layout.
Overview
Git worktrees create isolated working directories that share the same repository, allowing:
- Work on multiple branches simultaneously
- Isolated test environments
- Clean baseline for new features
- No stashing or switching required
Core principle: All worktrees live in ~/.local/share/worktrees/ following XDG conventions, consistent with lazyworktree.
Default tool: Use lazyworktree when available (preferred). Fall back to raw git worktree commands only when lazyworktree is not installed.
Announce at start: “I’m using the UsingGitWorktrees skill to set up an isolated workspace.”
XDG Data Layout
All worktrees are organized under ~/.local/share/worktrees/:
~/.local/share/worktrees/
├── vdemeester/
│ ├── home/
│ │ ├── main-lively-panda/
│ │ └── sakhalin-upgrade-bold-oak/
│ └── tektoncd-plumbing/
│ └── terraform-persistent-state/
└── tektoncd/
└── pipeline/
└── feature-new-resolver-calm-quartz/
Structure: ~/.local/share/worktrees/<org>/<repo>/<name>/
Note: lazyworktree auto-generates names like <branch>-<adjective>-<noun>. The org/repo is resolved automatically from the git remote.
Creating Worktrees with lazyworktree (Preferred)
Check availability
command -v lazyworktree >/dev/null 2>&1
Create a worktree
# Non-interactive creation — prints the worktree path to stdout
WORKTREE_PATH=$(lazyworktree create --from-branch <branch> --silent)
cd "$WORKTREE_PATH"
Examples:
# From an existing branch
WORKTREE_PATH=$(lazyworktree create --from-branch main --silent)
# → ~/.local/share/worktrees/public/home/main-lively-panda
# From a feature branch
WORKTREE_PATH=$(lazyworktree create --from-branch feature/sakhalin-upgrade --silent)
# → ~/.local/share/worktrees/public/home/feature-sakhalin-upgrade-bold-oak
# From a PR
WORKTREE_PATH=$(lazyworktree create --from-pr 42 --silent)
# Carry uncommitted changes to the new worktree
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --with-change --silent)
# With post-create setup command (runs inside new worktree)
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --silent --exec "go mod download")
Run commands in a worktree
# Execute a command inside a worktree without cd-ing
lazyworktree exec -w <worktree-name> "go test ./..."
lazyworktree exec -w <worktree-name> "make build"
List worktrees
# JSON output (richest — includes dirty, ahead/behind, last_active)
lazyworktree list --json
# Paths only (for scripting)
lazyworktree list --pristine
# Standard git output
git worktree list
# Interactive TUI
lazyworktree
Delete a worktree
# Removes worktree and cleans up the branch
lazyworktree delete --silent <worktree-path>
Rename a worktree
# From inside the worktree
lazyworktree rename <new-name> --silent
# Explicit worktree
lazyworktree rename <worktree-path> <new-name> --silent
Fallback: Raw Git Commands
Only use when lazyworktree is not available.
Determining Org and Repo
Extract organization and repository name from git remote:
REMOTE_URL=$(git remote get-url origin)
if [[ "$REMOTE_URL" =~ git@[^:]+:([^/]+)/([^/.]+) ]]; then
ORG="${BASH_REMATCH[1]}"
REPO="${BASH_REMATCH[2]}"
elif [[ "$REMOTE_URL" =~ https://[^/]+/([^/]+)/([^/.]+) ]]; then
ORG="${BASH_REMATCH[1]}"
REPO="${BASH_REMATCH[2]}"
fi
REPO="${REPO%.git}"
Create worktree manually
WORKTREE_BASE="$HOME/.local/share/worktrees"
BRANCH_NAME="feature/user-authentication"
BRANCH_PATH=$(echo "$BRANCH_NAME" | tr '/' '-')
WORKTREE_PATH="$WORKTREE_BASE/$ORG/$REPO/$BRANCH_PATH"
mkdir -p "$WORKTREE_BASE/$ORG/$REPO"
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME"
cd "$WORKTREE_PATH"
Remove worktree manually
git worktree remove ~/.local/share/worktrees/<org>/<repo>/<name>
# Or force:
git worktree remove --force ~/.local/share/worktrees/<org>/<repo>/<name>
After Creation: Setup and Verify
Use --exec on create or exec -w after creation to run setup and verification.
Auto-Detect and Run Project Setup
Preferred: Use --exec during creation:
# Go
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --silent --exec "go mod download")
# Node.js
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --silent --exec "npm install")
# Python
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --silent --exec "uv sync")
# NixOS (home repository)
WORKTREE_PATH=$(lazyworktree create --from-branch feature-x --silent --exec "make dry-build")
Or after creation with exec:
lazyworktree exec -w <worktree-name> "go mod download"
Verify Clean Baseline
Run tests without switching directories:
lazyworktree exec -w <worktree-name> "go test ./..."
lazyworktree exec -w <worktree-name> "cargo test"
lazyworktree exec -w <worktree-name> "pytest"
lazyworktree exec -w <worktree-name> "npm test"
lazyworktree exec -w <worktree-name> "make build"
If tests fail:
- Report failures clearly
- Ask whether to proceed or investigate
- Document known issues
If tests pass:
- Report success, show test count and duration
- Confirm ready for work
Report Worktree Ready
Worktree created successfully
Location: ~/.local/share/worktrees/myorg/myrepo/feature-auth-calm-willow
Branch: feature/auth
Tests: ✓ 47 passing (2.3s)
Ready to implement feature
Managing Worktrees
List All Worktrees
git worktree list
Navigate Between Worktrees
# Direct path
cd ~/.local/share/worktrees/myorg/myrepo/<name>
# Interactive selection via lazyworktree TUI
lazyworktree
Prune Deleted Worktrees
git worktree prune
Quick Reference
| Situation | lazyworktree | Raw git |
|---|---|---|
| Create | lazyworktree create --from-branch <b> --silent |
git worktree add <path> -b <b> |
| Create + setup | lazyworktree create --from-branch <b> --silent --exec "cmd" |
N/A |
| Create from PR | lazyworktree create --from-pr <n> --silent |
N/A |
| Exec in worktree | lazyworktree exec -w <name> "cmd" |
cd <path> && cmd |
| List (JSON) | lazyworktree list --json |
N/A |
| List (paths) | lazyworktree list --pristine |
git worktree list |
| Delete | lazyworktree delete --silent <path> |
git worktree remove <path> |
| Rename | lazyworktree rename <new-name> --silent |
N/A |
| Navigate | lazyworktree (TUI) |
cd <path> |
| Prune | git worktree prune |
git worktree prune |
Common Patterns for the Home Repository
Building a NixOS Configuration
cd ~/src/home
WORKTREE_PATH=$(lazyworktree create --from-branch feature/sakhalin-upgrade --silent)
cd "$WORKTREE_PATH"
make host/sakhalin/build
Working on Multiple Hosts
cd ~/src/home
WT1=$(lazyworktree create --from-branch feature/rhea-jellyfin --silent)
WT2=$(lazyworktree create --from-branch feature/aion-audio --silent)
cd "$WT1" && make host/rhea/build
cd "$WT2" && make host/aion/build
Working on Tekton Pipeline
cd ~/src/tektoncd/pipeline/main
WORKTREE_PATH=$(lazyworktree create --from-branch feature/new-resolver --silent)
cd "$WORKTREE_PATH"
go test ./...
Integration with Pi Extension
The pi git extension (~/.pi/agent/extensions/git/) provides:
- Tool:
git_worktree— AI can create/remove/list/exec in worktrees programmaticallyaction: "list"— lists worktrees with dirty/ahead/behind/last_active + notes from lazyworktreeaction: "create"+exec: "cmd"— creates worktree and runs setup commandaction: "exec"+branch: "<name>"+exec: "cmd"— runs command inside a worktreeaction: "remove"— removes worktree (lazyworktree also cleans up the branch)action: "note"— read/write worktree notes (see below)
- Commands:
/worktreeor/wt— interactive worktree management
Both the tool and commands use lazyworktree when available, falling back to raw git.
Worktree Notes
Worktree notes are short descriptions attached to worktrees via lazyworktree note. They serve as working memory — ephemeral context tied to a branch’s lifecycle — complementing the durable save_session/save_learning/save_plan tools.
How Notes Flow
| Moment | Direction | What happens |
|---|---|---|
| Session starts in a worktree | lazyworktree → AI | Note is auto-injected as context on first turn (if a note exists) |
| AI browses worktrees | lazyworktree → AI | git_worktree list includes first line of each note |
| AI saves a session | AI → lazyworktree | save_session_to_history auto-updates the worktree note with session date + description |
| Worktree is deleted | — | Note dies naturally; session/learning/plan persists in ~/.local/share/ai/ |
Reading Notes (AI tool)
# Read current worktree's note
git_worktree({ action: "note" })
# Read a specific worktree's note by name
git_worktree({ action: "note", branch: "bump-knative-pkg-and-k8s" })
Writing Notes (AI tool)
# Set a worktree note
git_worktree({ action: "note", branch: "my-worktree", exec: "Working on auth refactor\nBlocked on upstream PR #123" })
Auto-Update on save_session
When save_session_to_history is called, the extension automatically appends/updates a line in the worktree note:
🤖 pi (2026-03-17): bump-knative-pkg-k8s-035-tekton-pipeline
This preserves any manually written notes and only updates the AI session line. So when you open lazyworktree later, you can see at a glance what the AI last worked on in each worktree.
Best Practices for Notes
- Keep notes short — they appear in the lazyworktree TUI, one-liners are best
- Use notes for current state — “3 tests failing, waiting for upstream fix”
- Use
save_sessionfor full story — the session summary captures the complete narrative - Write a note after creating a worktree — helps future AI sessions (and you) understand the worktree’s purpose
CLI Usage (for reference)
# Read
lazyworktree note show <worktree-name>
# Write (from stdin)
echo "Working on feature X" | lazyworktree note edit --input - <worktree-name>
# Write (opens editor)
lazyworktree note edit <worktree-name>
Integration with Other Skills
Before UsingGitWorktrees:
- Use Brainstorming to clarify what feature needs isolation
- Ensure design is validated before creating worktree
After UsingGitWorktrees:
- Use WritingPlans to create implementation plan
- Use TestDrivenDevelopment for implementation in worktree
- Use Git skill for branching and commit workflows
Cleanup after work:
# From main repo, merge work back
git merge feature/user-authentication
# Remove worktree (lazyworktree also deletes the branch)
lazyworktree delete --silent ~/.local/share/worktrees/myorg/myrepo/<name>
# Or with raw git (branch cleanup is manual)
git worktree remove ~/.local/share/worktrees/myorg/myrepo/<name>
git branch -d feature/user-authentication
Common Mistakes
❌ Creating Worktrees in Random Locations
Problem: Worktrees scattered across filesystem
Fix: Always use lazyworktree or ~/.local/share/worktrees/<org>/<repo>/
❌ Using raw git when lazyworktree is available
Problem: Inconsistent naming, no org/repo detection via gh/glab
Fix: Default to lazyworktree create --from-branch <b> --silent
❌ Proceeding with Failing Tests
Problem: Can’t distinguish new bugs from pre-existing issues Fix: Report failures, get explicit permission to proceed
❌ Forgetting to Remove Old Worktrees
Problem: Disk space waste, confusion about active work
Fix: Regularly run git worktree list and remove completed work
❌ Committing from Wrong Worktree
Problem: Changes go to wrong branch
Fix: Always verify current branch before committing: git branch --show-current
Red Flags
Never:
- Create worktrees outside
~/.local/share/worktrees/ - Skip org/repo structure in path
- Proceed with failing tests without explicit permission
- Leave old worktrees around indefinitely
- Commit to wrong branch (verify with
git branch --show-current)
Always:
- Prefer lazyworktree over raw git commands
- Use
--silentflag for non-interactive scripting - Capture the output path:
WORKTREE_PATH=$(lazyworktree create ...) - Auto-detect and run project setup
- Verify clean test baseline
- Report clear status when worktree is ready
- Clean up worktrees when work is merged