个人工作站 › 调查报告 ← 返回报告清单

速览(5 分钟)

是什么
git worktree
一个仓库同时 checkout 多个分支到不同目录,共享对象库
为什么 AI 工具用它
任务隔离
每个 AI agent 在独立 worktree 中工作,互不干扰,磁盘开销极小
核心命令
git worktree add
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 中设置 worktree: true 的子代理
命名规则
由 pi 内部管理(managed worktree)
清理方式
子代理结束后自动清理;worktree: false 可覆盖
手动介入
通常不需要;残留时跑 git worktree prune

Claude 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 会话
命名规则
用户自定义(如 ~/work/feature-a)
清理方式
用户手动 git worktree remove;/resume 可选择其他 worktree 的会话
手动介入
是——worktree 由用户管理,Claude 不自动创建/清理

Cursor

Cursor Anysphere

Cursor Agent 使用自己的 Checkpoints 机制(本地文件快照)做安全回退,而非 git worktree。但 Cursor Agent 可以执行终端命令,包括 git worktree——用户或 agent 可以在 Cursor 中手动创建 worktree 来隔离任务。
何时创建
不自动创建;用户可通过 Agent 终端执行 git worktree 命令
命名规则
用户自定义
清理方式
用户手动;Checkpoints 与 worktree 独立
手动介入
是——worktree 不是 Cursor 的内建机制

GitHub Copilot Workspace

Copilot Workspace GitHub

GitHub 的 Copilot Workspace 在云端 VM 中为每个 issue/task 创建隔离环境。其底层使用 git worktree 机制为并行任务提供独立的工作目录,每个任务在独立 worktree 中执行,完成后通过 PR 合回。
何时创建
每个 Workspace 任务自动创建
命名规则
GitHub 内部按 issue/task ID 管理
清理方式
任务完成(PR 合并/关闭)后自动清理
手动介入
通常不需要;云端环境由 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 是共享的:

组件作用域说明
HEADper-worktree每个 worktree 可以指向不同分支或 commit
indexper-worktree每个 worktree 有独立的暂存区,互不影响
refs/heads/shared分支引用在主仓库的 .git/refs/ 中,所有 worktree 看到同一组分支
refs/(per-worktree)per-worktree通常为空;git 2.29+ 支持 per-worktree refs
objects/shared所有 worktree 共享
configshared全局配置在主仓库;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
本地并行 AI agent 隔离 hotfix

git 子模块

仓库内嵌仓库
  • ✅ 独立版本控制
  • ✅ 可指向不同远程仓库
  • ❌ 不是为并行开发设计的
  • ❌ 操作复杂(submodule update)
  • ❌ 不共享对象库
  • ❌ 解决的是「代码复用」不是「并行」
代码复用 多仓库项目

shallow clone

部分历史克隆
  • ✅ 下载体积小(--depth=1)
  • ✅ CI 场景省带宽
  • ❌ 独立仓库,不共享对象
  • ❌ 无本地分支历史
  • ❌ 不能 git log 到 depth 之外
  • ❌ 不是 worktree 的替代品
CI 省带宽 一次性构建

Docker 容器

容器化隔离
  • ✅ 完全隔离(OS 级)
  • ✅ 环境一致性(依赖/版本)
  • ❌ 重量级(镜像拉取/启动慢)
  • ❌ 文件系统隔离,调试不便
  • ❌ 需要 Docker daemon
  • ❌ 过度——纯 git 分支隔离不需要
环境隔离 CI/CD Dev Container
选型建议
本地多分支并行(人工或 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.02015git worktree 命令引入(add / remove / list)
2.9.02016增加 --detach、--lock 选项
2.11.02017增加 git worktree move
2.20.02018增加 git worktree repair
2.29.02020支持 per-worktree refs
2.43+2023+持续改进 sparse-checkout 交互

相关文档

这份报告属于 个人工作站 › 调查报告 ← 返回报告清单
返回调查报告