# How Pi Web Handles Dirty Worktree Detection and Force Removal

> Learn how Pi Web detects dirty worktrees using Git errors and handles force removal with a force query parameter for uncommitted changes.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: internals
- Published: 2026-07-25

---

**Pi Web detects dirty worktrees by catching Git errors in [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts), returning HTTP 409 when uncommitted changes block removal, and allowing force deletion via a `force` query parameter that adds the `--force` flag to `git worktree remove`.**

Managing Git worktrees safely requires handling uncommitted changes that block deletion. In the `agegr/pi-web` repository, **dirty worktree detection** is implemented through a combination of Git error parsing and structured API responses. This article examines how the application detects dirty states and provides a force-removal mechanism to discard changes when necessary.

## Detecting Dirty Worktrees in [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts)

The worktree management logic resides in **[`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts)**, where the `removeWorktree()` function orchestrates deletion attempts. When invoked, the function first validates the target through `listWorktrees()` to ensure it is not the main worktree and filters out prunable or missing entries (lines 38‑49).

The function then executes the standard Git command:

```bash
git worktree remove <path>

```

If the worktree contains uncommitted or untracked changes, Git aborts the operation and returns an error containing the word *"dirty"*. The `removeWorktree()` wrapper catches this failure and processes the error through `extractGitError()` (lines 26‑30), which sanitizes the Git output before re‑throwing it as a standard `Error` object.

## API Route Error Translation and the 409 Response

The HTTP layer in **[`app/api/worktrees/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/worktrees/route.ts)** bridges Git errors and client responses. When handling a DELETE request, the route invokes `removeWorktree()` with the `force` parameter set to `false` by default.

If the function throws an error containing *"dirty"*, the route intercepts this specific case and responds with **HTTP 409 Conflict** and a JSON payload:

```json
{ "dirty": true }

```

This structured response signals to the frontend that the worktree contains unsaved changes, triggering the display of a *Force Remove* button in the user interface.

## Implementing Force Removal with the `--force` Flag

When the user opts to force removal, the client repeats the DELETE request with the query parameter `force=1`. The API route detects this flag and calls `removeWorktree()` with `force=true`, which modifies the Git command construction at line 19 of [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts).

With the force flag enabled, the function appends `--force` to the Git command:

```bash
git worktree remove --force <path>

```

This instructs Git to discard all uncommitted and untracked changes before removing the worktree directory. Upon successful execution, the route returns **HTTP 200 OK**, confirming the forced deletion.

## Client-Side Integration

The frontend interprets the 409 status code to reveal the *Force Remove* option, while the 200 status confirms successful deletion. The client implementation uses standard fetch requests to communicate with the worktree API:

```typescript
// Normal removal attempt - fails if dirty
await fetch(`/api/worktrees?path=${encodeURIComponent(worktreePath)}`, {
  method: "DELETE",
});

// Force removal - discards uncommitted changes
await fetch(`/api/worktrees?path=${encodeURIComponent(worktreePath)}&force=1`, {
  method: "DELETE",
});

```

## Summary

- **Validation first**: `listWorktrees()` in [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts) filters out invalid targets before attempting removal (lines 38‑49).
- **Error parsing**: `extractGitError()` converts Git failures into readable messages, specifically detecting *"dirty"* states (lines 26‑30).
- **Structured responses**: The API route returns HTTP 409 with `{ "dirty": true }` when uncommitted changes block deletion.
- **Force flag**: Adding `force=1` to the query string triggers `removeWorktree()` to append `--force` to the Git command (line 19).
- **Safe defaults**: The system defaults to safe removal and requires explicit user confirmation to discard changes.

## Frequently Asked Questions

### What happens when Pi Web tries to delete a dirty worktree?

When `removeWorktree()` in [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts) executes `git worktree remove` on a directory containing uncommitted changes, Git exits with an error. The API route catches this error, detects the *"dirty"* keyword in the message, and returns HTTP 409 Conflict with a JSON body indicating `dirty: true`.

### How does the force removal parameter work in Pi Web?

The client appends `force=1` as a query parameter to the DELETE request. The API route passes this boolean to `removeWorktree()`, which adds the `--force` flag to the Git command at line 19. This forces Git to delete the worktree and discard any uncommitted or untracked files without manual cleanup.

### Where is the dirty worktree detection logic located?

The detection spans two files: [`lib/worktree.ts`](https://github.com/agegr/pi-web/blob/main/lib/worktree.ts) handles Git error extraction via `extractGitError()` (lines 26‑30), while [`app/api/worktrees/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/worktrees/route.ts) interprets these errors and translates them into the 409 HTTP response that signals a dirty state to the client.

### What Git command does Pi Web use to remove worktrees?

For standard removal, Pi Web executes `git worktree remove <path>`. When force removal is requested via the API, it executes `git worktree remove --force <path>` to override dirty worktree protection.