Git Worktree 支持
在独立工作区中运行 CodeBuddy,实现并行开发和安全隔离。
概述
Git worktree 允许在同一仓库中同时拥有多个工作目录,每个目录可以检出不同的分支。CodeBuddy Code 利用这一特性提供:
- 并行开发:在不影响主工作区的情况下进行实验性开发
- 安全隔离:AI 的所有更改都在独立目录中进行
- 零存储开销:worktree 共享 Git 对象,不会复制整个仓库
- 子代理隔离:支持多个 AI 子代理在独立 worktree 中并行工作
- tmux 集成:可选在独立的 tmux 会话中运行
- 非 Git 支持:通过 WorktreeCreate/WorktreeRemove hooks,SVN、Perforce 等项目也能使用 worktree 隔离
快速开始
bash
# 自动生成名称创建 worktree
codebuddy --worktree
# 指定名称创建 worktree
codebuddy --worktree feature-auth
# 指定基础分支创建 worktree
codebuddy --worktree --worktree-branch origin/develop # 基于远程 develop 分支
codebuddy --worktree --worktree-branch feature/foo # 基于本地 feature/foo 分支
# 在 tmux 会话中运行(推荐用于长时间任务)
codebuddy --worktree --tmux
# 基于 PR/MR 创建 worktree(用于代码审查)
codebuddy --worktree "#123" # GitHub PR 编号
codebuddy --worktree "https://github.com/owner/repo/pull/123" # GitHub PR 链接
codebuddy --worktree "https://gitlab.com/owner/repo/-/merge_requests/456" # GitLab MR 链接
codebuddy --worktree "https://cnb.woa.com/owner/repo/-/pulls/789" # CNB PR 链接在会话中创建
已启动 CodeBuddy Code 会话后,可以通过自然语言请求创建 worktree:
> start a worktree
> work in a worktree
> 启动 worktreeAI 会自动调用 EnterWorktree 工具创建隔离工作目录并切换过去。
注意:只有明确提到 "worktree" 时才会触发,说 "帮我开一个分支" 或 "修复这个 bug" 不会自动创建 worktree。
CLI 参数
| 参数 | 说明 | 示例 |
|---|---|---|
--worktree [name] | 创建并进入 worktree | --worktree 或 --worktree my-feature |
--worktree-branch <branch> | 指定基础分支(需配合 --worktree) | --worktree-branch origin/develop 或 --worktree-branch feature/foo |
--tmux | 在 tmux 会话中运行(需要安装 tmux) | --worktree --tmux |
--tmux-classic | 使用传统 tmux 模式(不使用 popup) | --worktree --tmux --tmux-classic |
工作流程
创建 Worktree
当使用 --worktree 参数启动时:
- CodeBuddy 在
.codebuddy/worktrees/目录下创建新的 worktree - 确定基础分支:
- 如果指定了
--worktree-branch origin/xxx,基于远程分支origin/xxx - 如果指定了
--worktree-branch xxx,基于本地分支xxx - 如果未指定,默认基于远程默认分支(通常是
origin/main或origin/master)
- 如果指定了
- 自动创建对应的分支(如
worktree-feature-auth) - 将工作目录切换到 worktree
- 执行初始化(复制设置、创建符号链接、复制
.worktreeinclude文件等)
分支不存在时的行为:
- 如果指定的分支(远程或本地)不存在,会打印警告并自动降级到远程默认分支继续创建
- 不会中断启动流程
退出时的选择
当你退出 worktree 会话时,CodeBuddy 会检测变更并提供选项:
- 保留 Worktree:保留所有更改和分支,可以稍后继续
- 删除 Worktree:清理 worktree 和关联分支
- 保留但退出 tmux:(tmux 模式)保留 worktree 但关闭 tmux 会话
变更检测
退出前,CodeBuddy 会检测:
- 未提交的文件变更
- 未推送的提交
如果没有任何变更,worktree 会自动清理。
配置
在 settings.json 中配置 worktree 行为:
json
{
"worktree": {
"symlinkDirectories": ["node_modules", ".next", ".cache", "dist"]
}
}配置项
| 配置项 | 说明 | 默认值 |
|---|---|---|
symlinkDirectories | 从主仓库符号链接到 worktree 的目录 | [] |
符号链接目录可以避免在每个 worktree 中重复安装依赖,节省时间和磁盘空间。
同步本地忽略文件(.worktreeinclude)
.env.local、.env.development 等本地配置文件通常被 .gitignore 排除,但新 worktree 中同样需要它们才能正常运行。
解决方式:在仓库根目录创建 .worktreeinclude 文件,列出需要复制的文件(语法与 .gitignore 相同):
gitignore
# .worktreeinclude
# 列出需要复制到新 worktree 的本地文件
# 环境变量
.env.local
.env.development.local
.env.test.local
# 本地 IDE 配置
.vscode/settings.json
# 本地证书或密钥(如有)
certs/localhost.pem每次创建新 worktree 时,这些文件会自动从主仓库根目录复制过去。复用已有 worktree 时不会重新复制。
提示:
.worktreeinclude应该提交到 Git,这样团队成员都能受益。
Hook-based Worktree
默认情况下,worktree 功能依赖 Git 内置的 git worktree 命令。对于使用 SVN、Perforce 或没有版本控制的项目,可以通过配置 WorktreeCreate / WorktreeRemove hooks 来使用 worktree 隔离功能。
决策优先级
1. 配置了 WorktreeCreate hook? → 使用 hook 创建(即使在 Git 仓库中也优先使用 hook)
2. 在 Git 仓库中? → 使用 git worktree
3. 都不满足? → 报错并提示配置 hook核心规则:
- Hook 优先于 Git:配置了 WorktreeCreate hook 后,即使在 Git 仓库中也走 hook,不走
git worktree - 创建失败不降级:WorktreeCreate hook 失败时不会回退到 git worktree,直接报错
- 删除失败不阻塞:WorktreeRemove hook 失败只记录警告,不阻止退出流程
配置方式
在 .codebuddy/settings.json(项目级)或 ~/.codebuddy/settings.json(全局)中配置:
json
{
"hooks": {
"WorktreeCreate": [
{
"hooks": [
{
"type": "command",
"command": "bash ~/.codebuddy/hooks/worktree-create.sh"
}
]
}
],
"WorktreeRemove": [
{
"hooks": [
{
"type": "command",
"command": "bash ~/.codebuddy/hooks/worktree-remove.sh"
}
]
}
]
}
}两个 hook 独立配置——可以只配 WorktreeCreate 不配 WorktreeRemove(此时退出时不会自动清理,会提示手动删除目录)。
输入数据(stdin)
Hook 脚本通过 stdin 接收 JSON 格式的上下文数据。
WorktreeCreate 输入:
json
{
"hook_event_name": "WorktreeCreate",
"session_id": "abc123def456",
"cwd": "/Users/user/project",
"transcript_path": "/Users/user/.codebuddy/sessions/abc123/transcript.md",
"name": "feature-auth"
}| 字段 | 说明 |
|---|---|
name | worktree 名称(用户指定或系统自动生成) |
cwd | 当前工作目录 |
session_id | 当前会话 ID |
transcript_path | 对话记录文件路径 |
WorktreeRemove 输入:
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"
}| 字段 | 说明 |
|---|---|
worktree_path | 要删除的 worktree 绝对路径 |
输出与 Exit Code
WorktreeCreate:
- stdout:必须输出创建好的 worktree 绝对路径(取最后一行非空行)
- stderr:可输出日志,不影响路径解析
- exit code 0:成功,解析 stdout 中的路径
- exit code 非 0:创建失败,报错并退出(不降级到 git worktree)
bash
# 正确示例:日志输出到 stderr,路径输出到 stdout
echo "Initializing SVN checkout..." >&2
echo "/home/user/.codebuddy/worktrees/feature-auth"WorktreeRemove:
- 没有决定控制:任何 exit code 都不会阻止退出流程
- 失败仅记录警告日志
退出行为差异
与 Git worktree 不同,hook-based worktree 退出时始终显示 keep/remove 菜单,不做变更检测(因为非 Git 项目没有 git status)。
Hook 脚本模板
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"
# 在这里添加 VCS 初始化逻辑(SVN checkout、P4 sync、目录复制等)
cp -r "$CWD"/* "$WORKTREE_PATH/" 2>/dev/null || true
# 最后一行输出绝对路径到 stdout(必需)
echo "$WORKTREE_PATH"WorktreeRemove (~/.codebuddy/hooks/worktree-remove.sh):
bash
#!/bin/bash
INPUT=$(cat)
WORKTREE_PATH=$(echo "$INPUT" | jq -r '.worktree_path')
# 安全检查:确保路径在预期范围内
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"提示:脚本依赖
jq解析 JSON。macOS:brew install jq,Linux:apt install jq。
实战示例
SVN 项目:
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'"
}
]
}
]
}
}无 VCS 的项目(目录复制):
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 集成
使用 --tmux 参数可以在独立的 tmux 会话中运行 CodeBuddy:
bash
# 基本用法
codebuddy --worktree --tmux
# 使用传统模式(不使用 popup)
codebuddy --worktree --tmux --tmux-classictmux 要求
- tmux 版本 3.2 或更高(支持 popup 功能)
- 如果版本较低,会自动回退到传统模式
退出 tmux 会话
- 按
Ctrl+D或输入/exit退出 CodeBuddy - tmux 会话会根据你的选择保留或关闭
目录结构
your-repo/
├── .codebuddy/
│ └── worktrees/
│ ├── feature-auth/ # worktree 目录
│ │ ├── node_modules -> ../../node_modules # 符号链接
│ │ └── ...
│ └── fix-bug-123/
├── .worktreeinclude # 定义需要复制的本地文件(建议提交)
└── ...手动管理 Worktree
CodeBuddy Code 在会话退出时会自动处理 worktree 的清理。但有时需要在会话外手动管理——比如清理残留的 worktree,或者需要更灵活地控制分支和目录位置。
在会话外清理 Worktree
直接使用 Git 命令清理:
bash
# 查看当前所有 worktree
git worktree list
# 删除指定 worktree(worktree 内没有未提交改动时)
git worktree remove .codebuddy/worktrees/feature-auth
# 强制删除(有未提交改动时)
git worktree remove --force .codebuddy/worktrees/feature-auth
# 同时删除对应的分支
git branch -D worktree-feature-auth
# 清理失效的 worktree 引用(目录已删但 Git 还记着)
git worktree prune用 Git 直接创建 Worktree
有时需要检出已有分支,或者把 worktree 放到仓库目录之外,可以绕开 CodeBuddy Code 直接用 Git 创建,然后再在里面启动会话:
bash
# 新建分支并创建 worktree(放在仓库外)
git worktree add ../project-feature-a -b feature-a
# 检出已有分支
git worktree add ../project-bugfix bugfix-123
# 进入 worktree,启动 CodeBuddy Code
cd ../project-feature-a && codebuddy
# 用完后清理
git worktree remove ../project-feature-a这种方式适合需要把 worktree 放在特定位置、或者复用现有分支的场景。
子代理隔离
当让 CodeBuddy Code 启动多个子代理并行工作时,可以让每个子代理运行在独立的 worktree 中,避免文件冲突。
isolation: worktree 是什么
在自定义 Agent 的 frontmatter 中加上 isolation: worktree,每次用 Task 工具启动这个 Agent 时,系统会自动为它创建一个独立的 worktree,而不是在主仓库目录里直接运行。
这意味着:
- 多个子代理可以同时修改同名文件,互不影响
- 主仓库目录保持干净,子代理的临时改动不会污染它
- 子代理完成后,worktree 按需保留或删除
创建隔离型自定义 Agent
在 .codebuddy/agents/ 目录下创建 Markdown 文件:
markdown
---
name: isolated-worker
description: 在独立 worktree 中工作,不影响主仓库
isolation: worktree
---
你在一个独立的 git worktree 中运行。
请专注完成分配给你的任务,完成后汇报结果。使用效果
主 Agent 用 Task 工具启动该 Agent 时,会自动为它创建独立的 worktree。多个子代理可以同时工作,即使修改了相同的文件也不会冲突。
子代理完成后:
- 没有变更:worktree 自动删除
- 有变更:worktree 保留,主 Agent 会收到 worktree 位置信息
验证隔离效果
> 使用 isolated-worker agent,在当前目录创建 test.txt,写入 "hello"检查结果:
bash
# 主仓库里没有这个文件
ls test.txt
# → No such file or directory ✓
# 文件在子代理的 worktree 里
ls .codebuddy/worktrees/agent-xxx/test.txt
# → 存在 ✓典型使用场景
场景一:基于特定分支开发
问题:需要在 develop 分支上开发新功能,而不是基于 main 分支。
解决方案:
bash
# 基于远程 develop 分支创建 worktree
codebuddy --worktree feature-xxx --worktree-branch origin/develop
# 基于本地分支创建(保留本地未推送的提交)
codebuddy --worktree feature-yyy --worktree-branch my-local-branch场景二:并行处理紧急 Bug
问题:正在开发新功能,代码改了一半,突然需要修紧急 bug。
解决方案:
bash
# 终端 1:继续开发新功能
codebuddy --worktree feature-payment
# 终端 2:专门修 bug,互不干扰
codebuddy --worktree hotfix-login-crash两个 worktree 同时打开,互不影响。bug 修完提交 PR,再回到功能开发。
场景三:高风险重构
问题:想尝试大规模重构,但不确定能否成功,不想污染主仓库。
解决方案:
bash
codebuddy --worktree refactor-esm在会话中:
> 帮我把 src/core 目录从 CommonJS 迁移到 ESM结果:
- 成功:提交,推 PR,合并
- 失败:退出时选择 "Remove worktree",所有改动一键丢弃
场景四:审查 PR
问题:想在本地跑一下同事的 PR 代码,但不想污染工作目录。
解决方案:
bash
codebuddy --worktree "#456"在会话中:
> 帮我看看这次 PR 改了什么,有没有潜在问题
> 运行一下测试审查完直接退出,worktree 自动清理。
场景五:并行任务
问题:有多个独立任务(写文档、加测试、开发新接口),想分别推进。
解决方案:
bash
codebuddy --worktree task-docs --tmux
codebuddy --worktree task-tests --tmux
codebuddy --worktree task-new-api --tmux每个 worktree 让 AI 专注做一件事,配合 tmux 实现真正并行工作。
场景六:子代理协作
问题:大型任务需要多个 AI 并行处理不同模块。
解决方案:
首先创建隔离型 Agent(见上文 "子代理隔离" 章节),然后:
> 使用三个并行的 api-worker 子代理:
第一个处理 src/api/user/ 目录
第二个处理 src/api/order/ 目录
第三个处理 src/api/product/ 目录三个子代理各自在独立 worktree 中工作,即使修改了共享文件也不会冲突。
常见问题
Q: --worktree-branch 应该传远程分支还是本地分支?
严格区分:
--worktree-branch origin/xxx→ 使用远程分支(会先 fetch 最新代码)--worktree-branch xxx→ 使用本地分支(保留本地未推送的提交)
如果指定的分支不存在,会打印警告并降级到远程默认分支,不会中断启动。
Q:worktree 会占用很多磁盘空间吗?
不会。所有 worktree 共享 Git 对象数据库,只需要存储工作文件本身。如果配置了 symlinkDirectories,大型目录也会共享,几乎不占额外空间。
Q:复用已有 worktree 时,.env.local 等文件还会重新复制吗?
不会。复用时直接进入已有目录,跳过初始化。如需同步新配置,需删除 worktree 后重建:
bash
git worktree remove --force .codebuddy/worktrees/my-feature
git branch -D worktree-my-feature
codebuddy --worktree my-featureQ:worktree 里的提交会影响主仓库吗?
不会。worktree 有独立分支,提交只在该分支上。要合并到主分支,需走正常 PR 流程或手动 git merge。
Q:创建 worktree 中途断开了,留下残缺目录怎么办?
bash
git worktree remove --force .codebuddy/worktrees/<名称>
git branch -D worktree-<名称>然后重新创建即可。
Q:symlinkDirectories 配置了但没生效?
复用已有 worktree 时不会重新初始化。删除旧 worktree 重建一次即可。
Q:子代理隔离是安全沙箱吗?
不是。子代理在文件层面隔离,但权限与主 Agent 相同,理论上可操作 worktree 之外的文件。这个功能的目的是防止多个 Agent 之间的文件冲突,而非安全限制。
Q:配置了 WorktreeCreate hook 后还能用 Git Worktree 吗?
不能同时使用。Hook 优先级高于 Git——一旦配置了 WorktreeCreate hook,所有 worktree 操作都走 hook,即使在 Git 仓库中也是如此。要恢复使用 git worktree,删除 settings.json 中的 WorktreeCreate 配置即可。
Q:只配了 WorktreeCreate 没配 WorktreeRemove 会怎样?
创建正常工作,但退出时不会自动清理。系统会提示 worktree 目录保留在哪里,需要手动删除。
Q:Hook 脚本执行失败了怎么办?
WorktreeCreate 失败会直接报错,不会降级到 git worktree,检查脚本的 stderr 输出排查问题。WorktreeRemove 失败只记录警告,不影响退出流程。
Q:在非 Git 项目中使用 hook-based worktree,退出时为什么没有自动清理?
hook-based worktree 退出时始终显示 keep/remove 菜单,不进行变更检测(因为非 Git 项目没有 git status)。需要手动选择是否删除。
注意事项
- Git 仓库或 Hook:
--worktree需要 Git 仓库或配置 WorktreeCreate hook(非 Git 项目如 SVN、Perforce 可通过 hook 支持) - 分支命名:自动创建的分支以
worktree-为前缀 - 清理:长时间未使用的 worktree 不会自动清理,需要手动删除或使用
/rewind命令 - 符号链接:某些工具可能不支持符号链接的目录,请根据项目需求配置