# How to Manage Local Repositories, Worktrees, and Git Operations with Routa

> Master local repositories, worktrees, and Git operations with Routa. This tool isolates agent tasks using disposable worktree environments and prevents race conditions with repository locks.

- Repository: [Fengda Huang/routa](https://github.com/phodal/routa)
- Tags: how-to-guide
- Published: 2026-05-26

---

**Routa isolates agent operations by treating Git worktrees as first-class resources, creating disposable environments tracked in a database and serializing all Git commands through repository-specific locks to prevent race conditions.**

Managing concurrent Git operations across multiple AI agents requires strict isolation. Routa solves this through a dedicated worktree architecture centered in [`src/core/git/git-worktree-service.ts`](https://github.com/phodal/routa/blob/main/src/core/git/git-worktree-service.ts). This service creates isolated working directories for each task, persists their metadata to a database, and guarantees thread-safe access to the underlying Git repository.

## Core Architecture: The GitWorktreeService

The `GitWorktreeService` class is the single source of truth for all worktree operations in Routa. It encapsulates the complexity of Git worktree management behind a unified API that the Kanban orchestrator, UI panels, and background tasks consume.

**Key responsibilities include:**

- **Persistence management** – Maintains a `WorktreeStore` database record for every worktree, ensuring the UI can query current state even after process restarts.
- **Path generation** – Calculates filesystem-safe paths under `~/.routa/worktrees/<workspace>/<codebase>/<branch-dir>`, with optional overrides via `options.worktreeRoot`.
- **Git abstraction** – Routes all Git commands through the platform bridge's `execGit` function, which handles proper escaping and configurable timeouts for both Node server and Tauri desktop environments.

As implemented in `phodal/routa`, the service uses an internal `repoLocks` Map to serialize operations per repository, preventing corruption of the `.git/worktrees` directory when multiple agents act simultaneously.

## The Worktree Lifecycle

Routa manages worktrees through a predictable seven-step workflow that spans from task creation to cleanup.

### Request and Creation

When a task enters a development column, the orchestrator calls `GitWorktreeService.createWorktree(codebaseId, opts)` at line 98 of the service file. This method generates a unique branch name, creates the worktree directory, and persists the record.

Branch names follow the pattern `wt/<label-or-uuid>` and are sanitized using the internal `branchToSafeDirName` utility (line 47) to ensure compatibility across Windows, macOS, and Linux filesystems.

### Filesystem Layout

By default, worktrees live at:

```text
~/.routa/worktrees/<workspace>/<codebase>/<branch-dir>

```

The `getWorktreeBaseDir` helper (line 53) constructs this path, respecting the `options.worktreeRoot` override when provided. This isolation prevents agents from interfering with the main working directory or other active worktrees.

### Git Operations and Persistence

All Git invocations flow through `execGit` (line 30), which executes commands via the platform bridge. After the Git worktree is created on disk, the service inserts a `Worktree` row via `worktreeStore.add`, linking the filesystem path to the task model defined in [`src/core/models/task.ts`](https://github.com/phodal/routa/blob/main/src/core/models/task.ts).

### Validation and Health Checks

Before allowing a user to switch to a task, the UI calls `validateWorktree` (line 64). This method verifies directory existence and checks for the presence of a `.git` file (not directory), confirming the worktree remains healthy after crashes or long pauses.

### Cleanup and Removal

When tasks complete or stale worktrees are detected, `GitWorktreeService.removeWorktree` (line 8) removes the directory and optionally deletes the associated branch via the `deleteBranch` option. This automatic cleanup prevents disk space exhaustion in long-running Routa instances.

## Concurrency Safety with Repository Locks

Routa prevents race conditions through a `repoLocks` Map that stores `Promise<void>` objects keyed by repository path. The `withRepoLock` wrapper sets the lock **before** any `await` statement, ensuring that only one operation touches a given repository's `.git/worktrees` metadata at a time.

The lock releases automatically in a `finally` block, guaranteeing that concurrent requests to create, remove, or prune worktrees for the same codebase execute sequentially rather than interleaving.

## Database Integration

The service relies on `WorktreeStore` implementations (typically [`pg-worktree-store.ts`](https://github.com/phodal/routa/blob/main/pg-worktree-store.ts) for PostgreSQL or in-memory variants for testing) to maintain state. Each worktree record includes:

- `id`: UUID reference stored in `task.worktreeId`
- `codebaseId`: Link to the parent repository
- `worktreePath`: Absolute filesystem location
- `branch`: Associated Git branch name
- `status`: Current lifecycle state

This persistence layer allows the Kanban orchestrator in [`src/core/kanban/workflow-orchestrator-singleton.ts`](https://github.com/phodal/routa/blob/main/src/core/kanban/workflow-orchestrator-singleton.ts) to provision worktrees asynchronously while the UI polls for status updates.

## Practical Implementation Examples

### Creating a Worktree for a Task

```typescript
import { GitWorktreeService } from '@/core/git/git-worktree-service';
import { InMemoryWorktreeStore } from '@/core/db/pg-worktree-store';
import { InMemoryCodebaseStore } from '@/core/db/pg-codebase-store';

const worktreeService = new GitWorktreeService(
  new InMemoryWorktreeStore(),
  new InMemoryCodebaseStore()
);

async function provisionWorktree(codebaseId: string) {
  const wt = await worktreeService.createWorktree(codebaseId, {
    label: 'feature-xyz',
    // Optional: override default ~/.routa/worktrees location
    // worktreeRoot: '/tmp/custom-worktrees',
  });
  console.log('Worktree ready:', wt.worktreePath);
  return wt.id; // Store this on the task model
}

```

### Listing Worktrees for the UI Panel

```typescript
async function listForCodebase(codebaseId: string) {
  const worktrees = await worktreeService.listWorktrees(codebaseId);
  worktrees.forEach(wt => {
    console.log(`${wt.branch} → ${wt.worktreePath} [${wt.status}]`);
  });
}

```

### Validating Before User Access

```typescript
async function ensureHealthy(worktreeId: string) {
  const { healthy, error } = await worktreeService.validateWorktree(worktreeId);
  if (!healthy) {
    throw new Error(`Worktree is broken: ${error}`);
  }
}

```

### Cleanup After Task Completion

```typescript
async function cleanupWorktree(worktreeId: string) {
  await worktreeService.removeWorktree(worktreeId, { deleteBranch: true });
  console.log('Worktree removed and branch deleted');
}

```

## Summary

- **Centralized service** – All worktree logic lives in [`src/core/git/git-worktree-service.ts`](https://github.com/phodal/routa/blob/main/src/core/git/git-worktree-service.ts), providing a consistent API for creation, validation, and removal.
- **Database-backed state** – Worktrees persist as `Worktree` records via `pg-worktree-store`, linked to tasks through `task.worktreeId`.
- **Race-condition prevention** – The `repoLocks` Map serializes Git operations per repository, protecting `.git/worktrees` integrity.
- **Default isolation** – Worktrees reside under `~/.routa/worktrees/` with OS-safe branch naming (`wt/<label-or-uuid>`).
- **Lifecycle integration** – The Kanban orchestrator automatically provisions worktrees when tasks enter development columns and cleans them up upon completion.

## Frequently Asked Questions

### How does Routa prevent Git corruption when multiple agents run simultaneously?

Routa uses a `repoLocks` Map to serialize operations per repository. Before executing any Git command, the service acquires a lock specific to that repository's path, ensuring that only one operation modifies the `.git/worktrees` directory at a time. The lock releases automatically after the operation completes, even if an error occurs.

### Can I customize where Routa stores worktrees on disk?

Yes. While the default location is `~/.routa/worktrees/<workspace>/<codebase>/`, you can override this by passing `worktreeRoot` in the options object when calling `GitWorktreeService.createWorktree`. This allows you to place worktrees on faster disks or dedicated volumes.

### What happens if a worktree becomes corrupted or is deleted externally?

The `validateWorktree` method checks both directory existence and the presence of a `.git` file (worktrees use a `.git` file pointing to the main repository, not a directory). If validation fails, the UI can prompt for recreation or cleanup, ensuring agents never attempt to operate in broken environments.

### How does the Kanban board connect tasks to specific worktrees?

The task model in [`src/core/models/task.ts`](https://github.com/phodal/routa/blob/main/src/core/models/task.ts) includes an optional `worktreeId?: string` field. When the workflow orchestrator moves a task to a development column, it calls `createWorktree` and stores the returned UUID in this field. This creates a durable link between the task card and its isolated working directory.