# How Roo Code Handles Git Worktree Detection and Inclusion

> Discover how Roo Code detects git worktrees using CLI commands and includes untracked assets via a .worktreeinclude file. Learn about its efficient file management.

- Repository: [Roo Code/Roo-Code](https://github.com/RooCodeInc/Roo-Code)
- Tags: internals
- Published: 2026-04-26

---

**Roo Code detects git worktrees by executing native git CLI commands and parsing porcelain output, while inclusion of untracked assets relies on a `.worktreeinclude` file that intersects with `.gitignore` patterns to selectively copy files using platform-native tools.**

Roo Code’s worktree service provides platform-agnostic **git worktree detection and inclusion** capabilities without depending on VS Code APIs. Located in the `RooCodeInc/Roo-Code` repository, this pure Node.js implementation uses `child_process` to execute git commands directly, enabling reliable repository root discovery, worktree enumeration, and intelligent copying of untracked files into newly created worktrees.

## Detecting Git Worktrees

The worktree detection layer identifies repository boundaries, current worktree context, and all registered worktrees through a series of standardized git commands.

### Repository Root and Current Worktree Discovery

The service locates the repository root by executing `git rev-parse --show-toplevel`. In [`packages/core/src/worktree/worktree-service.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/core/src/worktree/worktree-service.ts), the `WorktreeService.getGitRootPath` method (lines 49‑55) runs this command and returns the absolute path or `null` if the directory is not within a git repository.

Similarly, `WorktreeService.getCurrentWorktreePath` (lines 61‑67) uses the identical command to determine the active worktree path. To identify the current branch, the service runs `git rev-parse --abbrev-ref HEAD` (lines 73‑80), normalizing a detached `HEAD` state to `null` for consistent handling.

### Enumerating All Worktrees with Porcelain Parsing

To list all worktrees, Roo Code invokes `git worktree list --porcelain` (lines 86‑94). This machine-readable output is processed by `parseWorktreeOutput` (lines 48‑95), which extracts each worktree’s `path`, `branch`, `commitHash`, and status flags (bare, detached, locked). The parser identifies the current worktree by comparing normalized paths against the active directory.

### Path Normalization for Cross-Platform Reliability

Before comparison, all paths undergo normalization via `normalizePath` (lines 100‑110). This utility removes trailing slashes and resolves relative segments (`.` and `..`), ensuring reliable path matching across Windows and POSIX systems regardless of how the git CLI returns directory separators.

### Example: Listing Worktrees and Identifying the Current Context

```typescript
import { worktreeService } from "packages/core/src/worktree/worktree-service";

async function showWorktrees(cwd: string) {
  const worktrees = await worktreeService.listWorktrees(cwd);
  const current = await worktreeService.getCurrentWorktreePath(cwd);

  console.log("Repository root:", await worktreeService.getGitRootPath(cwd));
  console.log("Current worktree:", current);
  console.log("Detected worktrees:");
  worktrees.forEach(wt => {
    const marker = wt.isCurrent ? "← current" : "";
    console.log(`- ${wt.path} (branch: ${wt.branch || "detached"}) ${marker}`);
  });
}

// Call from any directory inside the repo
showWorktrees(process.cwd());

```

## Including Untracked Files with .worktreeinclude

When creating new worktrees, developers often need to bring over untracked assets like compiled binaries or cached dependencies. Roo Code implements this through the **WorktreeIncludeService**, which respects both `.worktreeinclude` and `.gitignore` to prevent copying tracked files.

### Detecting the Include File Presence

The service checks for inclusion directives at two levels. The `hasWorktreeInclude` function (lines 43‑49) tests the filesystem for a `.worktreeinclude` file in the source directory. For branches that have not been checked out, `branchHasWorktreeInclude` (lines 57‑66) uses `git cat-file -e <branch>:.worktreeinclude` to verify existence without switching branches.

### The Intersection Logic: Filtering by Both Rules

Copying operates on an intersection principle: a file must be listed in **both** `.worktreeinclude` and `.gitignore` to qualify for copying. This ensures only intentionally ignored untracked assets are migrated, never repository source files.

The `copyWorktreeIncludeFiles` function (lines 17‑30) orchestrates the process:

1. **Validation** – Aborts if either `.worktreeinclude` or `.gitignore` is missing.
2. **Pattern Parsing** – `parseIgnoreFile` splits each file into arrays of patterns, stripping comments and blank lines.
3. **Matcher Construction** – Uses the `ignore` npm package to create matchers for both files.
4. **Intersection Detection** – `findMatchingItems` (lines 91‑118) iterates over the source directory’s top-level entries, skips the `.git` folder, and retains only paths that both matchers ignore.
5. **Copy Execution** – For each match, the service uses `fs.copyFile` for files or `copyDirectoryWithProgress` (lines 97‑123) for directories.

### Platform-Specific Copy Implementation

`copyDirectoryWithProgress` implements platform-optimized transfer mechanics. On Windows, it executes `robocopy`; on POSIX systems, it uses `cp -r`. The function polls the target directory size to provide real-time progress callbacks reporting cumulative bytes copied and the current item name.

### Example: Creating a Worktree with Untracked Assets

```typescript
import {
  worktreeService,
  worktreeIncludeService,
} from "packages/core/src/worktree";

async function createWorktreeWithInclude(
  cwd: string,
  path: string,
  baseBranch = "main"
) {
  // 1. Detect current repository state
  const repoRoot = await worktreeService.getGitRootPath(cwd);
  if (!repoRoot) throw new Error("Not a git repository");

  // 2. Create the worktree (new branch `featureX`)
  const result = await worktreeService.createWorktree(repoRoot, {
    path,
    branch: "featureX",
    baseBranch,
    createNewBranch: true,
  });
  if (!result.success) throw new Error(result.message);

  // 3. Copy untracked files if .worktreeinclude exists on the base branch
  const hasInclude = await worktreeIncludeService.branchHasWorktreeInclude(
    repoRoot,
    baseBranch
  );
  if (hasInclude) {
    await worktreeIncludeService.copyWorktreeIncludeFiles(
      repoRoot,
      path,
      ({ bytesCopied, itemName }) => {
        console.log(`Copying ${itemName} … (${bytesCopied} bytes)`);
      }
    );
  }

  console.log("Worktree ready at", path);
}

// Execute from within the repository
createWorktreeWithInclude(process.cwd(), "./temp/featureX");

```

## Key Source Files

| File | Responsibility | Location |
|------|---------------|------------|
| [`worktree-service.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-service.ts) | Repository root detection, worktree enumeration, branch resolution, and worktree creation/deletion | [`packages/core/src/worktree/worktree-service.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/core/src/worktree/worktree-service.ts) |
| [`worktree-include.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-include.ts) | `.worktreeinclude` detection, existence checking on branches, and untracked file copying with progress | [`packages/core/src/worktree/worktree-include.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/core/src/worktree/worktree-include.ts) |
| [`worktree.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree.ts) | TypeScript type definitions for `Worktree`, `BranchInfo`, and related interfaces | [`packages/types/src/worktree.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/types/src/worktree.ts) |
| Test suites | Platform verification of detection and inclusion logic | [`packages/core/src/worktree/__tests__/worktree-service.spec.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/core/src/worktree/__tests__/worktree-service.spec.ts) and [`worktree-include.spec.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-include.spec.ts) |

## Summary

Roo Code’s approach to **git worktree detection and inclusion** follows a strict two-layer architecture:

- **Detection Layer** – Executes `git rev-parse` and `git worktree list --porcelain` to identify repository roots, current worktrees, and all registered worktrees, with rigorous path normalization for cross-platform compatibility.
- **Inclusion Layer** – Validates `.worktreeinclude` against `.gitignore` to copy only files present in both lists, using native platform copy commands (`robocopy` or `cp`) with progress reporting.

This Node.js implementation remains independent of editor-specific APIs, enabling robust worktree management in any environment where Git is available.

## Frequently Asked Questions

### How does Roo Code detect the current git worktree?

Roo Code runs `git rev-parse --show-toplevel` via `WorktreeService.getCurrentWorktreePath` in [`worktree-service.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-service.ts) (lines 61‑67) to determine the active worktree path. It compares this result against the list generated by `git worktree list --porcelain` to mark the matching entry as current using normalized path comparison.

### What is the purpose of the .worktreeinclude file in Roo Code?

The `.worktreeinclude` file directs Roo Code to copy specific untracked files—such as build artifacts or dependencies—into newly created worktrees. Unlike `.gitignore` which excludes files from version control, `.worktreeinclude` acts as a positive filter for the copying process, working in conjunction with `.gitignore` to identify which untracked assets should migrate.

### How does Roo Code determine which untracked files to copy to a new worktree?

Roo Code applies intersection logic: a file must be ignored by **both** `.worktreeinclude` and `.gitignore` to qualify. The `findMatchingItems` function in [`worktree-include.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-include.ts) (lines 91‑118) creates ignore matchers from both files, then selects only directory entries that pass both filters, ensuring no tracked source files are ever copied.

### Why does Roo Code use platform-specific commands like robocopy instead of Node.js fs.copyFile for directories?

While `fs.copyFile` handles individual files, `copyDirectoryWithProgress` in [`worktree-include.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/worktree-include.ts) (lines 97‑123) uses `robocopy` on Windows and `cp -r` on POSIX systems to leverage native optimized copy mechanisms. These tools provide better performance for large directory trees and enable size-polling for accurate progress reporting during the copy operation.