WorktreeService manages Git worktrees in Emdash, enabling each task to run in an isolated Git environment. It handles worktree creation, deletion, file preservation, and integrates with the WorktreePoolService for instant task starts.
Overview
Worktrees are created at../worktrees/{slugged-name}-{hash} on branch {prefix}/{slugged-name}-{hash}. The branch prefix defaults to emdash and is configurable in app settings.
Key features:
- Isolated environments: Each task gets its own worktree with a unique branch
- File preservation: Automatically copies gitignored files (
.env,.envrc, etc.) from main repo to worktree - Configurable patterns: Custom preserve patterns via
.emdash.jsonat project root - Safety checks: Prevents accidental removal of main repository
- Worktree pooling: Integrates with WorktreePoolService for instant worktree claiming
Core Methods
createWorktree
Create a new Git worktree for an agent task.Absolute path to the main Git repository
Human-readable task name (will be slugified for branch/directory names)
Database project ID
Optional base branch override (e.g.,
origin/develop). Falls back to project settings if not provided.Stable worktree ID (derived from absolute path hash)
Original task name
Created branch name (e.g.,
emdash/fix-bug-a7f)Absolute path to worktree directory
Associated project ID
Worktree status
ISO 8601 timestamp
- Generates slugified branch name:
{prefix}/{slugged-name}-{3-char-hash} - Resolves base ref from project settings or parameter
- Fetches latest base ref from remote (with fallback)
- Creates worktree via
git worktree add -b {branch} {path} {baseRef} - Preserves gitignored files from main repo to worktree
- Pushes new branch to remote (if
pushOnCreatesetting is enabled)
removeWorktree
Remove a worktree and delete its branch (local and remote).Main repository path
Worktree ID from
createWorktreeOptional explicit worktree path (used if worktree not in registry)
Optional branch name to delete
- Verifies worktree path is not the main repository
- Confirms path is actually a Git worktree (via
git worktree list --porcelain) - Prevents removal of main worktree
- Only removes directories matching worktree path patterns
- Validates worktree is safe to remove
- Runs
git worktree remove --force {path} - Prunes stale worktree metadata:
git worktree prune - Deletes local branch:
git branch -D {branch} - Deletes remote branch:
git push origin --delete {branch}(if remote exists) - Cleans up filesystem directory
listWorktrees
List all worktrees for a project, filtered by managed branch prefixes.Main repository path
Array of worktree metadata objects
getWorktreeStatus
Get the current Git status of a worktree (staged, unstaged, untracked files).Absolute path to worktree
File Preservation
preserveProjectFilesToWorktree
Copy gitignored files from main repo to worktree using project-specific or default patterns.Source directory (main repository)
Destination directory (worktree)
Custom Preserve Patterns
Create.emdash.json at project root to customize:
- Uses minimatch for glob patterns
- Matches against both filename and full relative path
- Automatically adds
**/prefix for nested matches - Dot files (e.g.,
.env) are matched by default
Worktree Naming
Branch Name Format
- Prefix: Configurable via
repository.branchPrefixsetting (default:emdash) - Slugged name: Task name converted to lowercase kebab-case
- Hash: 3-character alphanumeric hash for uniqueness
Directory Name Format
Stable Worktree IDs
Worktree IDs are generated from the absolute path hash:WorktreePoolService Integration
createWorktreeFromBranch
Create a worktree from an existing branch (used by WorktreePoolService for instant claiming).Existing Git branch to checkout
Optional explicit worktree path (for pool claiming)
- Claiming pre-created worktrees from the pool
- Restoring worktrees after app restart
- Checking out existing PR branches
registerWorktree
Register an externally-created worktree (e.g., from WorktreePoolService).Worktree metadata to register
Base Branch Resolution
fetchLatestBaseRef
Resolve and fetch the latest base branch for a project.- Explicit
baseReffrom project settings (e.g.,origin/develop) - Project’s current branch from settings
- Remote default branch (via
git remote show origin) - Fallback:
origin/main(ormainfor local-only repos)
- Returns empty string for
remote - Uses local branch names (e.g.,
maininstead oforigin/main) - Skips remote fetch/push operations
- Validates local branch existence with
git rev-parse
Error Handling
Common Errors
Worktree path already exists:Error Tracking
Worktree operations are tracked via PostHog telemetry:Location
Source:src/main/services/WorktreeService.ts
Singleton export:
Related Services
- WorktreePoolService (
src/main/services/WorktreePoolService.ts): Pre-creates worktrees for instant task starts - DatabaseService (
src/main/services/DatabaseService.ts): Persists project/task metadata - ProjectSettingsService (
src/main/services/ProjectSettingsService.ts): Stores base branch preferences
See Also
- WorktreePoolService - Worktree pooling and instant claiming
- TaskLifecycleService - Task orchestration
- Project Configuration -
.emdash.jsonoptions