设想同时开两个 AI 编程聊天:一个帮博客写小记,另一个调整网络小册。两项任务各有上下文,甚至各自约定了分支名,但工具都在同一个项目目录里工作。
前一个聊天刚改完 README,后一个又读写了同一个文件。等到提交时,文章、组件和导航混在一起,得重新辨认哪些修改属于哪项任务。
聊天分开了,磁盘上的文件却还是同一份。Git worktree 解决的正是这个问题:让同一个仓库同时拥有多个工作目录,各自编辑、暂存和提交,再明确地整合成果。
已经有分支,为什么还要多一个目录?
分支记录一条开发线当前指向哪次提交。只在原目录创建两个分支,磁盘上依然只有一份正在使用的文件;切换分支,会改变这个目录检出的内容。
Worktree 增加的是可以同时使用的工作目录。给写小记和改小册分别准备一份目录后,两个 AI 就能各自打开 README,而不用轮流切换原目录的版本。Git worktree 官方说明
这几个概念可以按职责区分:
| 对象 | 保存什么 | 在并行任务中起什么作用 |
|---|---|---|
| 分支 | 开发线当前指向的提交 | 给任务成果一个可引用的名字 |
| 工作目录 | 实际可读写的文件 | 让两项任务的编辑分别落盘 |
暂存区 index | 下一次提交准备收录的内容 | 分开组织两项任务的提交 |
HEAD | 当前检出的分支或提交 | 确定每份目录正在什么位置工作 |
通常可以让一个独立任务对应一个目录和一个分支。但 worktree 也能直接检出某次提交,处于 detached HEAD 状态;它与命名分支并不是必须一一绑定的关系。
先跑一次:同名文件会不会互相覆盖?
配套实验用真实 Git 创建一个临时仓库,把 note.txt 的初始内容提交为 draft。随后从同一个提交建立 alpha 和 beta 两个 worktree,分别写入不同内容。
在本站仓库根目录运行下面的公开入口,需要 Python 3.10+、Git 2.31+,只用 Python 标准库。2026-11-04 实测环境为 Python 3.13.3、Git 2.50.1(Apple Git-155):
python3 examples/git-worktree/user_code/main.py实验不调用模型。它按固定顺序扮演两项任务,在系统临时目录执行真实 Git 命令,完成后自动清理。实验提交使用专用虚构身份,不修改用户的 Git 配置。
两项任务提交后,文件和分支的位置是:
| 目录 | 检出的分支 | note.txt 的内容 |
|---|---|---|
| repo | main | draft |
| alpha | task/alpha | A: protocol note |
| beta | task/beta | B: network note |
脚本会输出八行 PASS。其中两个检查尤其值得看:alpha 暂存修改后,beta 的暂存区仍保存 draft;alpha 提交后,beta 已经可以读取那次提交对象,但自己的 HEAD 和文件都没有自动前进。
这两个观察分别证明了提交准备各自独立和仓库历史共享。它们来自真实本地 Git 操作,不是字典模拟,也不代表两个在线 Agent 已经完成了协作。
多份目录,怎样连到同一个仓库?
新增 worktree 时,Git 检出文件,并为它保存一份专属管理信息。新目录顶层的 .git 通常是文本文件,指向主仓库 .git/worktrees/ 下的对应位置。
例如执行 git worktree add -b task/alpha ../alpha main 后,可以把主要结构理解为:
repo/.git/
├── objects/ 共享的 Git 对象库
├── refs/heads/ 共享的分支引用
└── worktrees/alpha/
├── HEAD alpha 的检出位置
└── index alpha 的暂存区
alpha/
├── .git 指向上面的管理目录
└── note.txt alpha 实际编辑的文件这里省略了其他管理文件。每份 worktree 的 HEAD、index 分开保存,提交对象和大部分引用共享,仓库配置默认也共享。因而不能把“文件独立”理解成“所有 Git 状态都独立”。结构依据见 Git 仓库布局。
配套脚本通过 git rev-parse --git-common-dir 和 git rev-parse --git-path index 核对这种关系,不硬编码管理目录的实际名称。创建多个 worktree 无需各自维护一套独立历史,但每份检出的文件、依赖和构建缓存仍然占用磁盘。
Git 默认还会拒绝把同一个分支同时检出到第二份 worktree。两个目录若都推进同一个分支引用,就会使它们各自文件和暂存区与分支位置的关系变得难以管理。并行工作通常采用不同分支,或者直接检出提交;不要靠绕过检查来组织任务。
各自改好了,为什么合并时还会冲突?
回到实验:alpha 和 beta 都修改了 note.txt 的同一行。在各自目录里编辑时,两份内容都被保留下来。等到主目录先合入 alpha,再合入 beta,Git 才需要回答:最终这一行应该采用哪个版本?
第二次合并会报告冲突。脚本用 git diff --name-only --diff-filter=U 确认冲突文件为 note.txt,再执行 git merge --abort,验证主目录恢复为合并前的 alpha 版本。这个恢复检查从干净的工作目录开始;不要把它推广成“带着任意未提交修改也一定能完整撤回”。Git merge 的冲突与恢复说明
随后脚本再次合并,按预先规定的教学决定,把两条内容都保留下来:
A: protocol note
B: network note解决冲突、暂存并提交后,脚本确认两条任务分支都已成为 main 的祖先,再移除干净的 linked worktree。这个固定选择只服务于两条笔记的实验;真实代码需要根据需求决定如何组合,并重新运行检查。
因此,worktree 让两份编辑能够先各自成立,把协调放到显式整合时进行。它无法保证两项设计兼容。即使 Git 能自动合并,一项任务改了接口语义、另一项仍依赖旧语义,程序也可能出错。
AI 编程工具接上了哪一层?
有了目录,还需要让任务实际使用它。文件工具应相对于任务目录读写,启动测试和构建的命令也应设置对应的 cwd。如果聊天标着 alpha,工具却仍在主目录执行,创建 worktree 本身不会改变落点。
AI 工具可以把“选择起点、建立目录、准备环境、关联聊天、审阅成果”接成流程。以 Codex 为例,2026-11-04 核对的官方文档说明:Worktree 模式默认直接检出提交,处于 detached HEAD 状态,之后可以创建分支再提交、推送。目录隔离来自 Git,聊天与目录的关联则由应用管理。Codex Worktrees 官方文档
还要核对起点如何准备。手动运行 Git 从指定提交创建目录时,原目录尚未提交的修改、被忽略的 .env 不会顺便完整复制过去;配套实验实际验证了这两项。Codex 等工具可能另外搬运本地修改或准备环境,这属于应用附加行为,不能用来推断原生 Git 的复制规则。
开了 worktree,哪些东西仍会互相影响?
工作目录只是隔离的一部分。为博客并行启动两份开发服务时,它们仍可能都监听 3001;程序连接同一个数据库时,也仍然在修改同一份外部数据。需要为这些资源另行分配端口、数据库或测试数据。
Worktree 也不限制进程访问其他目录。AI 的文件权限、命令权限和聊天记忆,由它所处的运行环境管理。目录路径告诉工具“在哪工作”,不会自动构成安全沙箱。
收尾则要分别确认文件和提交:未提交成果是否保存,新的提交是否已经审阅、合入或明确保留。git status 干净只表示没有待提交的文件变化,不表示新提交已进入主分支。实验也验证了 Git 会拒绝直接移除有已跟踪文件修改的目录;正式任务仍需主动检查未跟踪文件、忽略文件和成果引用。
对博客这样的项目,我会把独立小记、网络章节和首页改版分配到不同 worktree。同一任务的连续调整留在原目录;一个功能如果必须先等另一个接口确定,就先确定交接约定。并行的收益来自任务能独立推进,而目录隔离让每项任务留下可单独审阅的成果。
如果还想看 Harness 怎样把任务 ID 绑定到目录,再让工具带着对应 cwd 执行,可以继续读Worktree Isolation 思想篇及其实践篇。