| English | 交互演示 | 可运行实验 |
一个仓库里既要修 main 的紧急问题,又要让 Agent 在 feature 分支做较长的改动时,反复 switch、stash 和 restore 会把上下文混在一起。git worktree 提供多个工作目录,让每个目录检出自己的分支,同时复用同一个 Git 对象库。
它解决的是 Git 检出状态的并行,不是进程、端口、数据库、仓库外缓存或环境变量的隔离。多个 worktree 能减少分支切换带来的文件覆盖,仍需要协调外部共享资源和最终集成。
假设主工作树在 main,需要新增一个目录给 feature/parallel:
common Git directory
objects/ commit、tree、blob 的共享对象库
refs/heads/main 共享的普通分支引用
refs/heads/feature/... 共享的普通分支引用
primary worktree
HEAD -> main
Index: primary 的下一次 commit 草稿
Working Tree: primary 的磁盘文件
feature worktree
HEAD -> feature/parallel
Index: feature 的下一次 commit 草稿
Working Tree: feature 的磁盘文件
feature 提交后,primary 可以直接读取这个提交对象并合入分支。合入 main 不会把 feature 工作树的 HEAD 自动切到 main。两处看到同一套对象和普通分支引用,却保留自己的 HEAD、Index 和已检出文件。
git worktree add <path> <commit-ish> 创建 linked worktree。官方手册明确指出,它与当前仓库共享除每个 worktree 文件以外的内容,HEAD、index 就是典型的独立文件。
共享范围包括对象库和大多数普通 refs。一个 worktree 创建或推进 feature/parallel 后,另一个 worktree 可以用该分支名解析同一个提交。每个 worktree 的 HEAD 指向自己正在检出的分支,Index 也独立,所以可以同时各自暂存不同的文件。
Git 对某些每工作树的伪引用有特殊处理,HEAD 是最常见的一项。日常并行开发时,用下面的边界判断即可:
同一对象库和普通分支引用:可以看到彼此已提交的 Git 对象
不同 HEAD、Index、Working Tree:可以独立检出、编辑、暂存
仓库外资源:Git 不负责锁定或隔离
从 main 目录创建一个新分支和新目录:
git worktree add -b feature/agent-docs ../project-feature main
git worktree list --porcelain
分别检查两个位置:
git status --short
git -C ../project-feature status --short
git rev-parse --git-common-dir
git -C ../project-feature rev-parse --git-common-dir
git rev-parse --git-path HEAD
git -C ../project-feature rev-parse --git-path HEAD
git rev-parse --git-path index
git -C ../project-feature rev-parse --git-path index
预期是两个 --git-common-dir 归到同一处,HEAD 和 index 路径不同。只在 main 目录执行 git add main-note.txt 时,feature 的 git diff --cached --name-only 不应出现这个文件;反过来也成立。
完成 feature 后,在主工作树按团队的集成方式操作:
git status --short
git merge --no-ff feature/agent-docs
git status --short
git -C ../project-feature status --short
需要移除工作树时,先确认里面没有待保留文件:
git -C ../project-feature status --short
git worktree remove ../project-feature
git worktree list
正常使用 git worktree remove,它会检查不安全的删除情况。目录被手工移除后,才用 git worktree prune 清理陈旧管理记录。可移动磁盘或网络位置的工作树可先 git worktree lock,避免暂时不可见时被误判为陈旧。
如果 main 已由 primary 检出,下面的命令默认失败:
git worktree add ../another-main main
Git 的限制避免两个目录同时以同一个普通分支作为 HEAD,使一个位置提交或 reset 后,另一个位置对分支尖端的理解失去明确边界。不同分支可以并行:
git worktree add -b feature/review ../project-review main
--force 能绕开某些 worktree 保护。只有理解已有检出、协作约定和恢复路径时才考虑它;日常 Agent 并行任务应为每个工作树分配独立分支,或使用 detached HEAD 做纯检查。
Worktree 只管理各自目录内的 Git 检出状态。下面这些资源会跨 worktree 共享或竞争:
.env、证书或生成目录。例如两个 Agent 都启动 localhost:3000,第二个进程会因端口被占用而失败;Git 的 worktree 机制不会报告原因。给每个任务分配端口、临时目录和测试数据命名空间,再把实际映射写进交接记录。
实验创建自己的 primary 和 feature 工作树,全部提交都在临时根目录内:
cd labs/git-mental-model/09-worktree
lab_path=$(bash setup.sh)
bash verify.sh "$lab_path"
sed -n '1,240p' "$lab_path/observations.txt"
sed -n '1,120p' "$lab_path/same-branch-results.txt"
bash cleanup.sh "$lab_path"
verify.sh 对真实 Git 状态做以下断言:
main-note.txt 与 feature-note.txt 在提交前只出现在各自 Index。main 检出,接受 feature/parallel 的检出。external-resource.txt 可由两处上下文写入,Git 没有为它提供隔离。实验关闭全局 Git 配置、签名和调用方 hooks。cleanup.sh 只删除带本实验标记且结构完整的临时根目录。
完整自测:
bash labs/git-mental-model/09-worktree/test.sh
先在 primary/main 和 feature/parallel 分别暂存一个文件:
| 操作 | primary 的 Index | feature 的 Index | 预期 |
|---|---|---|---|
primary 暂存 main-note.txt |
有 main-note.txt |
无 | 两份草稿独立 |
feature 暂存 feature-note.txt |
无 feature-note.txt |
有 | 两份草稿独立 |
再为已检出的 main 创建 worktree |
不适用 | 不适用 | Git 拒绝 |
为 feature/review 创建 worktree |
原有内容保持 | 原有内容保持 | Git 允许 |
改变条件是目标分支是否已经被另一个 worktree 检出。若任务只需在同一提交上运行只读检查,可考虑 detached HEAD;若需要提交,给每个 Agent 独立分支并明确谁负责最终合入。
每个 Agent 的记录至少包含:
worktree path: <absolute path>
branch and HEAD: <branch or detached> -> <oid>
Index state: clean | staged paths listed separately
working-tree state: clean | changed paths listed separately
integration owner and target branch: <person/agent> -> <branch>
external allocation: ports, temp directory, test-data namespace
这些字段让接手者可以区分“提交已共享,文件仍在另一个工作树”“本地草稿尚未提交”和“外部资源冲突”。git worktree list --porcelain 可作为路径、分支和 lock 状态的机器可读快照。