速览(5 分钟)
是什么
git worktree
一个仓库同时 checkout 多个分支到不同目录,共享对象库
为什么 AI 工具用它
任务隔离
每个 AI agent 在独立 worktree 中工作,互不干扰,磁盘开销极小
核心命令
git worktree add
git worktree list
git worktree remove
git worktree list
git worktree remove
创建 / 查看 / 删除
一句话理解
git worktree 让你在不切换分支的前提下,把另一个分支 checkout 到另一个目录。主仓库的 .git 是一个目录;worktree 的 .git 是一个文件,指向主仓库里的元数据。两个目录共享同一份 git objects——所以创建 worktree 几乎不占额外磁盘空间。
为什么 AI 工具用 worktree
AI 编码工具(pi、Claude Code、Cursor 等)的核心能力是并行执行多个编码任务。但传统 git 有一个根本限制:
传统痛点
一个 git 仓库只有一个工作目录。要切换分支就得 git checkout,未提交的改动要么 stash 要么先 commit。两个 agent 同时改同一个目录 → 文件冲突、状态混乱。
git worktree 是 git 原生解决这个问题的方案(2.5 版本引入,2015 年):
| 需求 | worktree 如何解决 |
|---|---|
| 两个 agent 同时工作在不同分支 | 每个 agent 一个独立 worktree 目录,互不干扰 |
| 不丢失主分支未提交的改动 | worktree 有独立的 index(暂存区),不影响主目录 |
| 磁盘开销不能太大 | 共享对象库,worktree 只存工作文件 + 少量元数据 |
| agent 结束后干净清理 | git worktree remove 一条命令移除 |
AI 工具 × worktree 生命周期
通用生命周期
1Agent 启动收到任务
→
2worktree add创建隔离目录
→
3独立编码读 / 写 / 测试
→
4commit提交到分支
→
5Agent 结束任务完成
→
6worktree remove清理目录
关键观察:步骤 2 和 6 由工具自动执行,用户通常不需要手动操作。但 agent 崩溃或超时时,worktree 可能残留——这就是第 8 章「常见坑」要解决的问题。
pi-coding-agent
pi @earendil-works/pi-coding-agent
pi 的 subagent / workflow 系统支持
worktree: true 选项,为每个子代理创建隔离的 git worktree。何时创建
workflow 中设置
workflow 中设置
worktree: true 的子代理命名规则
由 pi 内部管理(managed worktree)
由 pi 内部管理(managed worktree)
清理方式
子代理结束后自动清理;
子代理结束后自动清理;
worktree: false 可覆盖手动介入
通常不需要;残留时跑
通常不需要;残留时跑
git worktree pruneClaude Code
Claude Code Anthropic
Claude Code 的会话绑定目录。官方文档推荐用 git worktree 实现并行会话:「Since sessions are tied to directories, you can run parallel Claude sessions by using git worktrees.」
何时创建
用户手动创建 worktree,然后在各目录启动独立 Claude 会话
用户手动创建 worktree,然后在各目录启动独立 Claude 会话
命名规则
用户自定义(如
用户自定义(如
~/work/feature-a)清理方式
用户手动
用户手动
git worktree remove;/resume 可选择其他 worktree 的会话手动介入
是——worktree 由用户管理,Claude 不自动创建/清理
是——worktree 由用户管理,Claude 不自动创建/清理
Cursor
Cursor Anysphere
Cursor Agent 使用自己的 Checkpoints 机制(本地文件快照)做安全回退,而非 git worktree。但 Cursor Agent 可以执行终端命令,包括
git worktree——用户或 agent 可以在 Cursor 中手动创建 worktree 来隔离任务。何时创建
不自动创建;用户可通过 Agent 终端执行
不自动创建;用户可通过 Agent 终端执行
git worktree 命令命名规则
用户自定义
用户自定义
清理方式
用户手动;Checkpoints 与 worktree 独立
用户手动;Checkpoints 与 worktree 独立
手动介入
是——worktree 不是 Cursor 的内建机制
是——worktree 不是 Cursor 的内建机制
GitHub Copilot Workspace
Copilot Workspace GitHub
GitHub 的 Copilot Workspace 在云端 VM 中为每个 issue/task 创建隔离环境。其底层使用 git worktree 机制为并行任务提供独立的工作目录,每个任务在独立 worktree 中执行,完成后通过 PR 合回。
何时创建
每个 Workspace 任务自动创建
每个 Workspace 任务自动创建
命名规则
GitHub 内部按 issue/task ID 管理
GitHub 内部按 issue/task ID 管理
清理方式
任务完成(PR 合并/关闭)后自动清理
任务完成(PR 合并/关闭)后自动清理
手动介入
通常不需要;云端环境由 GitHub 管理
通常不需要;云端环境由 GitHub 管理
命令速查
创建
git worktree add <path> [branch]
# 创建 worktree 并 checkout 指定分支
git worktree add ../feat-x -b feat-x
# 创建 worktree 同时创建新分支 feat-x
git worktree add ../hotfix --detach
# 创建 detached HEAD 的 worktree(不跟踪分支)
git worktree add ../release --checkout-ignore-sparse
# 忽略 sparse-checkout 配置
| 参数 | 说明 |
|---|---|
<path> | worktree 目录路径(相对或绝对) |
[branch] | 要 checkout 的分支(省略则 detached HEAD) |
-b <branch> | 创建新分支 |
--detach | 强制 detached HEAD |
--lock | 创建后立即锁定(防止误删) |
--force | 强制(即使分支已被其他 worktree 使用) |
管理
git worktree list
# 列出所有 worktree(主仓库 + 所有链接 worktree)
git worktree list --porcelain
# 机器可读格式(脚本用)
git worktree move ../old-path ../new-path
# 移动 worktree 到新路径
git worktree lock ../path
# 锁定(防止 prune 误删)
git worktree unlock ../path
# 解锁
排查
git worktree prune
# 清理已手动删除的 worktree 的元数据残留
git worktree prune -v
# 显示详细清理信息
git worktree repair ../path
# 修复 .git 文件指向(移动/复制目录后)
cat ../path/.git
# 直接查看 .git 文件内容(应包含 gitdir: 行)
清理
git worktree remove ../feat-x
# 删除 worktree(有未提交改动时会拒绝)
git worktree remove --force ../feat-x
# 强制删除(即使有未提交改动)
git worktree lock --drop ../feat-x
# 移除锁定标记
注意
git worktree remove 只删除工作目录和 .git/worktrees/<name>/ 元数据。不会删除分支本身。分支还在,可以用 git branch -d 单独删除。
实战工作流
场景 1:人工并行开发
你在 main 上开发功能 A,突然需要修 hotfix 分支的紧急 bug——不想 stash 功能 A 的改动:
git worktree add ../hotfix hotfix/urgent-bug
Preparing worktree (checking out 'hotfix/urgent-bug')
HEAD is now at a1b2c3d fix: null check in parser
# 在 ../hotfix 目录修 bug,commit,push
# 主目录的功能 A 改动完全不受影响
git worktree remove ../hotfix
# 修完后清理
场景 2:AI agent 并行任务
用 pi 的 subagent workflow 并行执行两个任务:
# pi workflow 伪代码(实际由 pi 内部调用)
git worktree add /tmp/pi-task-1 -b task/refactor-api
git worktree add /tmp/pi-task-2 -b task/fix-tests
# agent-1 在 /tmp/pi-task-1 中重构 API
# agent-2 在 /tmp/pi-task-2 中修复测试
# 两者互不干扰,共享同一个 .git/objects
git worktree remove /tmp/pi-task-1
git worktree remove /tmp/pi-task-2
# 两个 agent 都结束后清理
场景 3:CI/CD 隔离构建
# CI pipeline 伪代码
git worktree add "$BUILD_DIR" --detach "$COMMIT_SHA"
# 在独立 worktree 中 checkout 指定 commit(detached)
# 构建 + 测试 + 打包
git worktree remove --force "$BUILD_DIR"
# 构建完成后清理(--force 因为可能有构建产物)
原理深潜
文件系统布局
以下是一个真实仓库创建 worktree 后的磁盘结构(基于 git 2.43 实测):
主仓库 repo/
repo/
├── .git/ ← 目录(主仓库)
│ ├── HEAD → ref: refs/heads/main
│ ├── config
│ ├── index ← 主仓库的暂存区
│ ├── objects/ ← 共享对象库
│ │ ├── aa/
│ │ ├── bb/
│ │ └── pack/
│ ├── refs/
│ │ ├── heads/
│ │ │ ├── main
│ │ │ └── feat-auth
│ │ └── tags/
│ ├── logs/
│ └── worktrees/ ← worktree 元数据
│ └── feature-auth/
│ ├── HEAD → ref: refs/heads/feat-auth
│ ├── index ← 该 worktree 的暂存区
│ ├── commondir → ../..(指向主 .git)
│ ├── gitdir → 指向 worktree 的 .git 文件
│ ├── logs/
│ └── refs/ ← per-worktree refs(通常空)
├── src/
└── .gitignore
worktree feature-auth/
feature-auth/
├── .git ← 文件(不是目录!)
│ └── 内容:
│ gitdir: /path/to/repo/.git/worktrees/feature-auth
├── src/
└── .gitignore
关键区别:
主仓库: .git 是目录
worktree: .git 是文件
文件内容 = gitdir: + 绝对路径
指向主仓库 .git/worktrees/<name>/
commondir 文件
.git/worktrees/feature-auth/commondir 的内容是 ../..——它告诉 git「共享目录(objects、config 等)在两个层级之上」,即主仓库的 .git/ 目录。这就是 worktree 和主仓库共享对象库的机制。
共享对象库
所有 worktree 通过 commondir 指向同一个 .git/objects/ 目录:
对象共享示意
.git/objects/ ← 只有一份,所有 worktree 共享
├── 5f/
│ └── 7a3b2... ← commit object
├── aa/
│ └── 1c9e0... ← blob object (file content)
└── pack/
└── pack-xxx.pack ← 打包对象
主仓库 worktree ──┐
├──→ 同一个 .git/objects/
feature-auth ──────┘
创建 worktree 的磁盘开销 ≈ 工作文件大小 + 少量元数据(~100 字节级)
不是线性增长——10 个 worktree 不会让 objects 膨胀 10 倍
refs 与 HEAD
每个 worktree 有自己独立的 HEAD 和 index(暂存区),但 refs 是共享的:
| 组件 | 作用域 | 说明 |
|---|---|---|
HEAD | per-worktree | 每个 worktree 可以指向不同分支或 commit |
index | per-worktree | 每个 worktree 有独立的暂存区,互不影响 |
refs/heads/ | shared | 分支引用在主仓库的 .git/refs/ 中,所有 worktree 看到同一组分支 |
refs/(per-worktree) | per-worktree | 通常为空;git 2.29+ 支持 per-worktree refs |
objects/ | shared | 所有 worktree 共享 |
config | shared | 全局配置在主仓库;per-worktree 可设 core.worktree |
Detached HEAD 在 worktree 中
用 --detach 或 checkout 一个 commit SHA 创建的 worktree,其 HEAD 直接指向一个 commit 而非分支。这在 CI 场景很常见——构建指定 commit 不需要分支名。AI 工具也常用 detached worktree 做一次性任务。
分支独占限制
硬限制:一个分支同一时间只能被一个 worktree checkout
git worktree add ../x main 会报错,因为 main 已经在主仓库被 checkout 了。这是 git 的安全机制——防止两个工作目录同时修改同一分支导致 refs 冲突。
所以 AI 工具为每个 agent 创建独立分支(或 detached HEAD),而不是多个 worktree 指向同一分支。
git worktree add ../dup main
fatal: 'main' is already used by worktree at '/path/to/main-repo'
对比与选型
git worktree 不是唯一的「多分支并行」方案。以下是四种常见替代方案的对比:
git worktree
同仓库多工作目录
- ✅ 零额外网络开销
- ✅ 共享对象库,磁盘极小
- ✅ git 原生,无额外依赖
- ✅ 分支/commit 实时可见
- ❌ 同分支不能两个 worktree
- ❌ 移动目录后需
repair
git 子模块
仓库内嵌仓库
- ✅ 独立版本控制
- ✅ 可指向不同远程仓库
- ❌ 不是为并行开发设计的
- ❌ 操作复杂(
submodule update) - ❌ 不共享对象库
- ❌ 解决的是「代码复用」不是「并行」
shallow clone
部分历史克隆
- ✅ 下载体积小(
--depth=1) - ✅ CI 场景省带宽
- ❌ 独立仓库,不共享对象
- ❌ 无本地分支历史
- ❌ 不能
git log到 depth 之外 - ❌ 不是 worktree 的替代品
Docker 容器
容器化隔离
- ✅ 完全隔离(OS 级)
- ✅ 环境一致性(依赖/版本)
- ❌ 重量级(镜像拉取/启动慢)
- ❌ 文件系统隔离,调试不便
- ❌ 需要 Docker daemon
- ❌ 过度——纯 git 分支隔离不需要
选型建议
本地多分支并行(人工或 AI agent)→ git worktree(最轻量、git 原生)CI 省带宽 →
git clone --depth=1(shallow clone)跨仓库代码复用 →
git submodule需要完全环境隔离(不同 OS 依赖)→ Docker / Dev Container
常见坑与排查
⚠ 磁盘空间告急
症状:磁盘空间不够,怀疑 git 仓库膨胀
→ git worktree list # 列出所有 worktree
→ du -sh .git/objects/ # 看对象库大小
objects 是共享的,不会因 worktree 数量线性增长
→ du -sh <每个 worktree 路径> # 工作文件才是大头
→ git worktree remove <不用的> # 清理不用的 worktree
→ git gc --aggressive # 压缩对象库(慎用,慢)
⚠ AI 工具崩溃后 worktree 残留
症状:agent 崩溃/超时,worktree 目录还在
→ git worktree list # 找到残留
→ cd <残留路径> && git status # 检查有无未提交改动
有未提交改动:
→ git diff # 看看改动是否值得保留
→ git stash # 或 commit 后再 remove
→ git worktree remove <path>
无未提交改动(或不需要):
→ git worktree remove --force <path> # 强制清理
如果目录已被手动 rm -rf:
→ git worktree prune # 清理元数据残留
⚠ 多 worktree 下 stash 混乱
症状:
git stash pop 应用了错误的改动
→ git stash list # 列出所有 stash
stash 是 per-repo 的,所有 worktree 共享同一个 stash 列表
→ git stash show -p stash@{n} # 确认是哪个 worktree 的
→ 避免在多个 worktree 中同时用 stash
→ 替代方案:用 worktree 隔离代替 stash
⚠ 移动目录后 worktree 报错
症状:
fatal: not a git repository 或 gitdir file points to non-existent location
→ cat .git # 查看 gitdir 指向
原因:worktree 的 .git 文件存的是绝对路径,移动后失效
→ git worktree repair <path> # 修复指向
或者:手动编辑 .git 文件中的 gitdir 路径
⚠
git worktree add 报分支已被使用
症状:
fatal: 'main' is already used by worktree at '...'
原因:一个分支同一时间只能被一个 worktree checkout
→ 创建新分支:git worktree add ../x -b my-new-branch
→ 或用 detached:git worktree add ../x --detach
→ 或强制(危险):git worktree add --force ../x main
附录
版本历史
| 版本 | 年份 | 变更 |
|---|---|---|
| 2.5.0 | 2015 | git worktree 命令引入(add / remove / list) |
| 2.9.0 | 2016 | 增加 --detach、--lock 选项 |
| 2.11.0 | 2017 | 增加 git worktree move |
| 2.20.0 | 2018 | 增加 git worktree repair |
| 2.29.0 | 2020 | 支持 per-worktree refs |
| 2.43+ | 2023+ | 持续改进 sparse-checkout 交互 |