Skip to content

Git Worktree Support

Run CodeBuddy in isolated workspaces for parallel development and safe isolation.

Overview

Git worktree allows you to have multiple working directories simultaneously within the same repository, each checked out to a different branch. CodeBuddy Code leverages this feature to provide:

  • Parallel development: Perform experimental development without affecting the main workspace
  • Safe isolation: All AI changes are made in a separate directory
  • Zero storage overhead: Worktrees share Git objects without duplicating the entire repository
  • Sub-agent isolation: Multiple AI sub-agents can work in parallel in independent worktrees
  • tmux integration: Optionally run in a dedicated tmux session
  • Non-Git support: SVN, Perforce, and other projects can also use worktree isolation via WorktreeCreate/WorktreeRemove hooks

Quick Start

bash
# Create a worktree with an auto-generated name
codebuddy --worktree

# Create a worktree with a specific name
codebuddy --worktree feature-auth

# Create a worktree based on a specific branch
codebuddy --worktree --worktree-branch origin/develop  # Based on remote develop branch
codebuddy --worktree --worktree-branch feature/foo     # Based on local feature/foo branch

# Run in a tmux session (recommended for long-running tasks)
codebuddy --worktree --tmux

# Create a worktree based on a PR/MR (for code review)
codebuddy --worktree "#123"                                    # GitHub PR number
codebuddy --worktree "https://github.com/owner/repo/pull/123" # GitHub PR URL
codebuddy --worktree "https://gitlab.com/owner/repo/-/merge_requests/456" # GitLab MR URL
codebuddy --worktree "https://cnb.woa.com/owner/repo/-/pulls/789" # CNB PR URL

Creating Within a Session

After starting a CodeBuddy Code session, you can create a worktree via natural language:

> start a worktree
> work in a worktree
> 启动 worktree

The AI will automatically invoke the EnterWorktree tool to create an isolated working directory and switch to it.

Note: This is only triggered when "worktree" is explicitly mentioned. Saying "create a branch for me" or "fix this bug" will not automatically create a worktree.

CLI Parameters

ParameterDescriptionExample
--worktree [name]Create and enter a worktree--worktree or --worktree my-feature
--worktree-branch <branch>Specify the base branch (requires --worktree)--worktree-branch origin/develop or --worktree-branch feature/foo
--tmuxRun in a tmux session (requires tmux installed)--worktree --tmux
--tmux-classicUse classic tmux mode (without popup)--worktree --tmux --tmux-classic

Workflow

Creating a Worktree

When starting with the --worktree parameter:

  1. CodeBuddy creates a new worktree under the .codebuddy/worktrees/ directory
  2. Determines the base branch:
    • If --worktree-branch origin/xxx is specified, uses the remote branch origin/xxx
    • If --worktree-branch xxx is specified, uses the local branch xxx
    • If not specified, defaults to the remote default branch (usually origin/main or origin/master)
  3. Automatically creates a corresponding branch (e.g., worktree-feature-auth)
  4. Switches the working directory to the worktree
  5. Runs initialization (copies settings, creates symlinks, copies .worktreeinclude files, etc.)

Behavior when the branch does not exist:

  • If the specified branch (remote or local) does not exist, a warning is printed and the creation falls back to the remote default branch
  • The startup process is not interrupted

Options on Exit

When you exit a worktree session, CodeBuddy detects changes and offers options:

  • Keep Worktree: Preserve all changes and the branch for later continuation
  • Remove Worktree: Clean up the worktree and associated branch
  • Keep but exit tmux: (tmux mode) Preserve the worktree but close the tmux session

Change Detection

Before exiting, CodeBuddy checks for:

  • Uncommitted file changes
  • Unpushed commits

If no changes are detected, the worktree is automatically cleaned up.

Configuration

Configure worktree behavior in settings.json:

json
{
  "worktree": {
    "symlinkDirectories": ["node_modules", ".next", ".cache", "dist"]
  }
}

Configuration Options

OptionDescriptionDefault
symlinkDirectoriesDirectories to symlink from the main repository to the worktree[]

Symlinked directories avoid redundant dependency installation in each worktree, saving time and disk space.

Syncing Local Ignored Files (.worktreeinclude)

Local configuration files like .env.local and .env.development are typically excluded by .gitignore, but new worktrees need them to function properly.

Solution: Create a .worktreeinclude file in the repository root listing files to copy (uses the same syntax as .gitignore):

gitignore
# .worktreeinclude
# List local files to copy to new worktrees

# Environment variables
.env.local
.env.development.local
.env.test.local

# Local IDE configuration
.vscode/settings.json

# Local certificates or keys (if any)
certs/localhost.pem

These files are automatically copied from the main repository root each time a new worktree is created. Files are not re-copied when reusing an existing worktree.

Tip: .worktreeinclude should be committed to Git so all team members benefit.

Hook-based Worktree

By default, the worktree feature relies on the built-in git worktree command. For projects using SVN, Perforce, or those without version control, you can use worktree isolation by configuring WorktreeCreate / WorktreeRemove hooks.

Decision Priority

1. WorktreeCreate hook configured? → Use hook to create (takes priority even in a Git repo)
2. In a Git repository?           → Use git worktree
3. Neither?                       → Error with a prompt to configure hooks

Core rules:

  • Hooks take priority over Git: Once a WorktreeCreate hook is configured, all worktree operations go through the hook, even in a Git repository
  • No fallback on failure: If the WorktreeCreate hook fails, it does not fall back to git worktree — it errors immediately
  • Removal failure does not block exit: A WorktreeRemove hook failure only logs a warning and does not prevent the exit process

Configuration

Configure in .codebuddy/settings.json (project-level) or ~/.codebuddy/settings.json (global):

json
{
    "hooks": {
        "WorktreeCreate": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash ~/.codebuddy/hooks/worktree-create.sh"
                    }
                ]
            }
        ],
        "WorktreeRemove": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash ~/.codebuddy/hooks/worktree-remove.sh"
                    }
                ]
            }
        ]
    }
}

The two hooks are configured independently — you can configure only WorktreeCreate without WorktreeRemove (in which case the worktree will not be automatically cleaned up on exit, and a prompt will ask you to manually delete the directory).

Input Data (stdin)

Hook scripts receive JSON-formatted context data via stdin.

WorktreeCreate input:

json
{
    "hook_event_name": "WorktreeCreate",
    "session_id": "abc123def456",
    "cwd": "/Users/user/project",
    "transcript_path": "/Users/user/.codebuddy/sessions/abc123/transcript.md",
    "name": "feature-auth"
}
FieldDescription
nameWorktree name (user-specified or auto-generated)
cwdCurrent working directory
session_idCurrent session ID
transcript_pathPath to the conversation transcript file

WorktreeRemove input:

json
{
    "hook_event_name": "WorktreeRemove",
    "session_id": "abc123def456",
    "cwd": "/Users/user/project",
    "transcript_path": "/Users/user/.codebuddy/sessions/abc123/transcript.md",
    "worktree_path": "/tmp/codebuddy-worktrees/feature-auth"
}
FieldDescription
worktree_pathAbsolute path of the worktree to be removed

Output and Exit Code

WorktreeCreate:

  • stdout: Must output the absolute path of the created worktree (the last non-empty line is used)
  • stderr: Logs can be written here without affecting path parsing
  • exit code 0: Success — the path in stdout is parsed
  • exit code non-0: Creation failed — errors out and exits (no fallback to git worktree)
bash
# Correct example: logs to stderr, path to stdout
echo "Initializing SVN checkout..." >&2
echo "/home/user/.codebuddy/worktrees/feature-auth"

WorktreeRemove:

  • No decision control: any exit code does not prevent the exit process
  • Failure only logs a warning

Exit Behavior Difference

Unlike Git worktrees, hook-based worktrees always show the keep/remove menu on exit without change detection (since non-Git projects don't have git status).

Hook Script Templates

WorktreeCreate (~/.codebuddy/hooks/worktree-create.sh):

bash
#!/bin/bash
set -e

INPUT=$(cat)
NAME=$(echo "$INPUT" | jq -r '.name')
CWD=$(echo "$INPUT" | jq -r '.cwd')

WORKTREE_PATH="$HOME/.codebuddy/worktrees/$NAME"
mkdir -p "$WORKTREE_PATH"

# Add VCS initialization logic here (SVN checkout, P4 sync, directory copy, etc.)
cp -r "$CWD"/* "$WORKTREE_PATH/" 2>/dev/null || true

# Output the absolute path to stdout on the last line (required)
echo "$WORKTREE_PATH"

WorktreeRemove (~/.codebuddy/hooks/worktree-remove.sh):

bash
#!/bin/bash

INPUT=$(cat)
WORKTREE_PATH=$(echo "$INPUT" | jq -r '.worktree_path')

# Safety check: ensure path is within the expected directory
if [[ "$WORKTREE_PATH" != "$HOME/.codebuddy/worktrees/"* ]]; then
    echo "Refusing to remove path outside worktrees directory: $WORKTREE_PATH" >&2
    exit 1
fi

rm -rf "$WORKTREE_PATH"

Tip: The scripts depend on jq for JSON parsing. macOS: brew install jq, Linux: apt install jq.

Real-world Examples

SVN project:

json
{
    "hooks": {
        "WorktreeCreate": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash -c 'INPUT=$(cat); NAME=$(echo $INPUT | jq -r .name); DIR=\"$HOME/.codebuddy/worktrees/$NAME\"; svn checkout https://svn.example.com/repo/trunk \"$DIR\" >&2 && echo \"$DIR\"'"
                    }
                ]
            }
        ],
        "WorktreeRemove": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash -c 'cat | jq -r .worktree_path | xargs rm -rf'"
                    }
                ]
            }
        ]
    }
}

Non-VCS project (directory copy):

json
{
    "hooks": {
        "WorktreeCreate": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash -c 'INPUT=$(cat); NAME=$(echo $INPUT | jq -r .name); CWD=$(echo $INPUT | jq -r .cwd); DIR=\"$HOME/.codebuddy/worktrees/$NAME\"; cp -r \"$CWD\" \"$DIR\" && echo \"$DIR\"'"
                    }
                ]
            }
        ],
        "WorktreeRemove": [
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": "bash -c 'cat | jq -r .worktree_path | xargs rm -rf'"
                    }
                ]
            }
        ]
    }
}

tmux Integration

Use the --tmux parameter to run CodeBuddy in a dedicated tmux session:

bash
# Basic usage
codebuddy --worktree --tmux

# Use classic mode (without popup)
codebuddy --worktree --tmux --tmux-classic

tmux Requirements

  • tmux version 3.2 or higher (for popup support)
  • Automatically falls back to classic mode if the version is lower

Exiting a tmux Session

  • Press Ctrl+D or type /exit to quit CodeBuddy
  • The tmux session will be preserved or closed based on your choice

Directory Structure

your-repo/
├── .codebuddy/
│   └── worktrees/
│       ├── feature-auth/      # worktree directory
│       │   ├── node_modules -> ../../node_modules  # symlink
│       │   └── ...
│       └── fix-bug-123/
├── .worktreeinclude           # defines local files to copy (recommended to commit)
└── ...

Manual Worktree Management

CodeBuddy Code automatically handles worktree cleanup when a session exits. However, sometimes you need to manage worktrees outside of a session — for example, cleaning up leftover worktrees or having more flexible control over branches and directory locations.

Cleaning Up Worktrees Outside a Session

Use Git commands directly:

bash
# List all current worktrees
git worktree list

# Remove a specific worktree (when there are no uncommitted changes)
git worktree remove .codebuddy/worktrees/feature-auth

# Force remove (when there are uncommitted changes)
git worktree remove --force .codebuddy/worktrees/feature-auth

# Also delete the corresponding branch
git branch -D worktree-feature-auth

# Prune stale worktree references (directory deleted but Git still tracks it)
git worktree prune

Creating Worktrees Directly with Git

Sometimes you need to check out an existing branch, or place the worktree outside the repository directory. You can bypass CodeBuddy Code and create worktrees directly with Git, then start a session inside:

bash
# Create a new branch and worktree (outside the repository)
git worktree add ../project-feature-a -b feature-a

# Check out an existing branch
git worktree add ../project-bugfix bugfix-123

# Enter the worktree and start CodeBuddy Code
cd ../project-feature-a && codebuddy

# Clean up when done
git worktree remove ../project-feature-a

This approach is suitable for scenarios where you need to place the worktree in a specific location or reuse an existing branch.

Sub-agent Isolation

When having CodeBuddy Code launch multiple sub-agents to work in parallel, each sub-agent can run in an independent worktree to avoid file conflicts.

What is isolation: worktree

Adding isolation: worktree to a custom Agent's frontmatter means that each time the Task tool launches this Agent, the system automatically creates an independent worktree for it instead of running directly in the main repository directory.

This means:

  • Multiple sub-agents can modify files with the same name simultaneously without affecting each other
  • The main repository directory stays clean — sub-agents' temporary changes do not pollute it
  • After a sub-agent finishes, the worktree is kept or removed as needed

Creating an Isolated Custom Agent

Create a Markdown file in the .codebuddy/agents/ directory:

markdown
---
name: isolated-worker
description: Works in an independent worktree without affecting the main repository
isolation: worktree
---

You are running in an isolated git worktree.
Focus on completing the task assigned to you, and report results when done.

How It Works

When the main Agent launches this Agent using the Task tool, an independent worktree is automatically created for it. Multiple sub-agents can work simultaneously, even modifying the same files without conflicts.

After a sub-agent finishes:

  • No changes: The worktree is automatically deleted
  • Has changes: The worktree is preserved, and the main Agent receives the worktree location information

Verifying Isolation

> Use the isolated-worker agent to create test.txt in the current directory with the content "hello"

Check the result:

bash
# The file does not exist in the main repository
ls test.txt
# → No such file or directory ✓

# The file is in the sub-agent's worktree
ls .codebuddy/worktrees/agent-xxx/test.txt
# → exists ✓

Typical Use Cases

Scenario 1: Developing Based on a Specific Branch

Problem: You need to develop a new feature on the develop branch rather than the main branch.

Solution:

bash
# Create a worktree based on remote develop branch
codebuddy --worktree feature-xxx --worktree-branch origin/develop

# Create based on a local branch (preserving local unpushed commits)
codebuddy --worktree feature-yyy --worktree-branch my-local-branch

Scenario 2: Handling Urgent Bugs in Parallel

Problem: You're in the middle of developing a new feature with half-written code, and an urgent bug needs fixing.

Solution:

bash
# Terminal 1: Continue developing the new feature
codebuddy --worktree feature-payment

# Terminal 2: Fix the bug separately, without interference
codebuddy --worktree hotfix-login-crash

Both worktrees are open simultaneously without affecting each other. Once the bug is fixed and a PR is submitted, switch back to feature development.

Scenario 3: High-Risk Refactoring

Problem: You want to attempt a large-scale refactor but aren't sure if it will succeed, and you don't want to pollute the main repository.

Solution:

bash
codebuddy --worktree refactor-esm

In the session:

> Help me migrate the src/core directory from CommonJS to ESM

Result:

  • Success: Commit, push PR, merge
  • Failure: Choose "Remove worktree" on exit — all changes are discarded with one click

Scenario 4: Reviewing a PR

Problem: You want to run a colleague's PR code locally without polluting your working directory.

Solution:

bash
codebuddy --worktree "#456"

In the session:

> Help me review what this PR changed and check for potential issues
> Run the tests

Exit when done — the worktree is automatically cleaned up.

Scenario 5: Parallel Tasks

Problem: You have multiple independent tasks (writing docs, adding tests, developing a new API) and want to work on them separately.

Solution:

bash
codebuddy --worktree task-docs --tmux
codebuddy --worktree task-tests --tmux
codebuddy --worktree task-new-api --tmux

Each worktree lets the AI focus on one thing, with tmux enabling true parallel work.

Scenario 6: Sub-agent Collaboration

Problem: A large task requires multiple AI agents to process different modules in parallel.

Solution:

First create an isolated Agent (see the "Sub-agent Isolation" section above), then:

> Use three parallel api-worker sub-agents:
  The first handles the src/api/user/ directory
  The second handles the src/api/order/ directory
  The third handles the src/api/product/ directory

Three sub-agents each work in independent worktrees — even if they modify shared files, there are no conflicts.

FAQ

Q: Should I pass a remote or local branch to --worktree-branch?

They are strictly distinct:

  • --worktree-branch origin/xxx → Uses the remote branch (fetches the latest code first)
  • --worktree-branch xxx → Uses the local branch (preserves local unpushed commits)

If the specified branch does not exist, a warning is printed and the creation falls back to the remote default branch without interrupting startup.

Q: Will worktrees take up a lot of disk space?

No. All worktrees share the Git object database and only need to store the working files themselves. With symlinkDirectories configured, large directories are also shared, resulting in virtually no extra space usage.

Q: When reusing an existing worktree, will files like .env.local be re-copied?

No. When reusing, the existing directory is entered directly, skipping initialization. To sync new configurations, remove the worktree and recreate it:

bash
git worktree remove --force .codebuddy/worktrees/my-feature
git branch -D worktree-my-feature
codebuddy --worktree my-feature

Q: Will commits in a worktree affect the main repository?

No. A worktree has its own branch, and commits are only made on that branch. To merge into the main branch, follow the normal PR process or manually run git merge.

Q: What if the worktree creation was interrupted, leaving an incomplete directory?

bash
git worktree remove --force .codebuddy/worktrees/<name>
git branch -D worktree-<name>

Then recreate it.

Q: symlinkDirectories is configured but not working?

Reusing an existing worktree does not re-run initialization. Remove the old worktree and recreate it.

Q: Is sub-agent isolation a security sandbox?

No. Sub-agents are isolated at the file level, but they have the same permissions as the main Agent and can theoretically access files outside the worktree. This feature is designed to prevent file conflicts between multiple Agents, not to enforce security restrictions.

Q: Can I still use Git Worktree after configuring a WorktreeCreate hook?

No, they cannot be used simultaneously. Hooks take priority over Git — once a WorktreeCreate hook is configured, all worktree operations go through the hook, even in a Git repository. To revert to using git worktree, remove the WorktreeCreate configuration from settings.json.

Q: What happens if I configure WorktreeCreate but not WorktreeRemove?

Creation works normally, but the worktree will not be automatically cleaned up on exit. The system will prompt you with the location of the worktree directory, which you need to manually delete.

Q: What should I do if the hook script fails?

A WorktreeCreate failure will error out immediately without falling back to git worktree — check the script's stderr output to diagnose the problem. A WorktreeRemove failure only logs a warning and does not affect the exit process.

Q: Why is there no automatic cleanup when exiting a hook-based worktree in a non-Git project?

Hook-based worktrees always show the keep/remove menu on exit without performing change detection (since non-Git projects don't have git status). You need to manually choose whether to delete it.

Important Notes

  • Git repository or hook required: --worktree requires a Git repository or a configured WorktreeCreate hook (non-Git projects like SVN and Perforce can use hooks)
  • Branch naming: Automatically created branches are prefixed with worktree-
  • Cleanup: Long-unused worktrees are not automatically cleaned up — they need to be manually deleted or cleaned using the /rewind command
  • Symlinks: Some tools may not support symlinked directories — configure based on your project's needs