- worktree 让同一个 Git 仓库同时拥有多个工作目录:共享提交历史,各自保留文件现场、HEAD 和暂存区。
- 它最初解决的是开发中途插入热修、同时检出多个分支等问题;Git 2.5 在 2015 年把早期脚本方案发展成正式功能。
- 分支保存历史方向,worktree 提供可同时存在的物理工作台;它比重复 clone 更轻,也免去频繁 stash 和切分支。
- 在 Agent 时代,一个任务一个 worktree 能隔离文件写入并支持并行,但不能自动消除合并冲突、共享服务冲突和错误决策。
你正在重构登录页,二十多个文件已经改到一半,测试还没恢复。线上突然传来消息:支付按钮坏了,需要马上修。
如果只有一个项目目录,你大概会先停下重构,检查有没有漏掉的未跟踪文件,再 stash、切到 main、拉出热修分支。修完以后,还要按相反顺序把刚才的现场拼回来。另一种办法是重新 clone 一份仓库,但下载、配置和目录管理又显得很重。
Git worktree 提供了第三条路:保留眼前这个凌乱却完整的现场,在旁边再摆一张干净的工作台。
git worktree add -b hotfix/payment ../shop-hotfix main
运行以后,../shop-hotfix 是一个新的目录,里面检出了从 main 出发的 hotfix/payment 分支。原来的登录页改动没有被收起,也没有被覆盖。你可以打开第二个编辑器窗口去修支付问题,结束后再回到原目录,屏幕上的文件仍停在离开时的样子。
这就是 worktree 最初最朴素的价值。十多年后,当同时工作的不再只是“你上午的任务”和“下午插进来的热修”,而是三四个会自主改文件、跑测试、提交代码的 Coding Agent,这张额外的工作台突然从小众技巧变成了并行开发的基础设施。
一、先分清仓库、分支与工作树
Worktree 直译是“工作树”。这个名字容易让人以为它是一种新的分支,或者仓库的完整副本。它其实更接近某个版本在硬盘上展开后的可编辑现场。
一个普通的非裸 Git 仓库里,平时就已经有一棵工作树:你能在编辑器里看到的源代码、图片和配置文件。git clone 或 git init 创建的这一个,官方称为 main worktree,也就是主工作树。通过 git worktree add 增加的目录叫 linked worktree,也就是关联工作树。
它们的关系可以先看成“一间档案室,连接多张书桌”。点击下面任一目录,只观察哪些东西共享,哪些东西独立。
ONE REPOSITORY · THREE DESKS
一个仓库怎样长出多个工作目录
提交一次,其他 worktree 立即能看见这个提交和分支移动。
这里有三个容易混在一起的概念:
- Repository,仓库:保存提交对象、分支引用和版本历史的共同档案室。
- Branch,分支:一个会随提交向前移动的名字,例如
main或feature/login。它指向历史中的某个提交,不是一份独立文件夹。 - Worktree,工作树:一个真实目录,里面有某个提交展开后的文件,以及这个目录自己的当前分支、
HEAD和暂存区。
因此,“创建分支”和“创建 worktree”做的事不同。分支给历史增加一个可移动的路标;worktree 给这个路标安排一张可以立即动手的物理工作台。
共享与独立同时存在
多个 worktree 共享同一个对象库和大部分 refs。你在 shop-hotfix/ 中提交一次,新的 commit 对象和 hotfix/payment 分支移动会立刻进入共同仓库;回到 shop/ 运行 git log --all,已经可以看到它。
但每棵 worktree 都有自己的:
- 工作目录中的文件状态;
HEAD,也就是当前查看的位置;- index,也就是通常所说的暂存区;
- 一部分正在进行的操作状态,例如 rebase 或 bisect。
这解释了为什么两个目录可以分别保留未提交修改,也解释了 Git 为什么默认不允许同一个本地分支同时被两个 worktree 检出。如果两张书桌同时推动同一个分支名,分支究竟应该跟着哪一边移动会变得含糊。Git 用这一限制提前挡住了危险状态。
一句话收束:仓库负责共享历史,worktree 负责隔离现场,分支负责标记每项工作的历史方向。
二、Worktree 从边缘脚本走进 Git
Worktree 不是为了 AI 发明的。它来自一个很早就存在的开发矛盾:Git 的分支很轻,但硬盘上的工作目录一次只能呈现一个检出状态。
早期用户已经会用 GIT_DIR、GIT_WORK_TREE 或手工符号链接,把同一仓库的元数据连接到多个目录。Git 源码也曾附带一个位于 contrib/workdir/ 的辅助脚本 git-new-workdir。contrib 可以理解为随项目提供、但没有完全成为核心命令的一组贡献工具。这个脚本能共享对象和 refs,却依赖符号链接,仓库本身也不充分了解还有哪些工作目录正在借用它,安全边界比较脆弱。
2015 年发布的 Git 2.5 加入了替代方案。发布说明没有把它描述成凭空出现的新创意,而是明确说:它用于替代
git-new-workdir,不再依赖符号链接,并让共享关系中的双方都知道彼此存在。这个版本当时仍把多工作树标为实验性功能,界面也可能继续变化。
最初的 Git 2.5 worktree 文档 只有少量核心能力:
add 用来增加工作树,prune 用来清理失效的管理记录。随后 Git 逐步补齐了生命周期管理:可以列出、锁定、移动、删除、修复 worktree,也加入了更稳妥的脚本输出和每棵工作树独立配置等能力。
这段历史里最重要的不是记住版本号,而是看清它的演化方向:
- 用户先用脚本解决“同一历史、多个目录”的真实需求。
- Git 把隐蔽的符号链接关系变成仓库明确管理的关联关系。
- 功能从“能再检出一份”发展为完整的创建、检查、移动、修复与清理流程。
Git 官方文档至今仍以一个突发热修作为典型例子:重构现场很乱,不想冒险 stash,就新建一棵临时 worktree 修复紧急问题。也就是说,worktree 的原生使命不是制造更多分支,而是让已经很轻的分支能够同时出现在不同目录里。
三、它与切分支、stash、重复 clone 的差别
这四种做法都可能让你“处理另一项工作”,但代价分布完全不同。
| 做法 | 工作目录 | Git 对象库 | 未提交现场 | 适合场景 |
|---|---|---|---|---|
git switch | 复用一个 | 共享 | 必须能安全切换 | 当前目录很干净,任务依次进行 |
git stash + 切换 | 复用一个 | 共享 | 临时打包后再恢复 | 短暂插入、改动容易完整收起 |
再 git clone | 新增一个 | 通常各自保存 | 天然隔离 | 需要完全独立的仓库配置或远端关系 |
git worktree add | 新增一个 | 共享 | 天然隔离 | 同一仓库的多个分支需要同时工作 |
Worktree 比重复 clone 轻,主要不是因为源代码文件消失了。每个 worktree 仍要在硬盘上展开一份被检出的文件;大型依赖目录也可能需要分别安装。省下的是重复的 Git 对象库,例如相同的 commit、tree 和 blob,以及重新 clone 和同步历史的成本。
它也不等同于 stash。Stash 像把桌面物品装进一个有标签的箱子,再清空原桌面;worktree 则是保留原桌面,直接打开第二张桌子。前者仍然是串行切换,后者允许两个现场同时存在。
Worktree 不是容器
文件目录隔离很容易让人产生过度联想。Worktree 不是 Docker 容器、虚拟机或权限沙箱。多个 worktree 仍可能共享:
- 同一台机器的端口,例如都想监听
3000; - 同一个开发数据库、缓存或云端测试环境;
- 用户目录里的全局配置、凭据和工具缓存;
- 仓库级 Git 配置与 hooks;
- 被代码写到 worktree 之外的文件。
所以 worktree 隔离的是仓库内的文件现场和 Git 操作状态,不是进程能接触到的一切资源。这条边界到了 Agent 并行阶段尤其重要。
四、用五步完成一次安全工作流
多数日常使用不需要记很多参数。沿着“查看、创建、工作、汇合、清理”走一遍,已经覆盖了最常见的热修与并行任务。
SAFE WORKFLOW
从创建到清理的一次完整操作
git worktree listshop/ → main
git worktree add -b hotfix/payment ../shop-hotfix mainshop/ → main shop-hotfix/ → hotfix/payment
cd ../shop-hotfix
# 修改、测试、提交hotfix/payment → f031c4
git switch main
git merge hotfix/paymentmain 包含支付修复
git worktree remove ../shop-hotfix
git branch -d hotfix/payment只剩 shop/ → main
查看已有工作树
git worktree list
输出会列出路径、当前提交和分支。它应该成为创建和清理前的第一个动作,因为一个你想使用的分支可能已经在另一个目录中工作。
如果脚本需要稳定格式,可以使用:
git worktree list --porcelain
创建新分支与新目录
最清楚的写法是同时给出新分支、目录和起点:
git worktree add -b hotfix/payment ../shop-hotfix main
它做了三件事:从 main 创建 hotfix/payment,创建 ../shop-hotfix 目录,再把新分支检出到这个目录。
如果分支已经存在,可以直接检出:
git worktree add ../shop-login feature/login
只想临时运行旧版本测试,不打算推动某个分支时,可以创建 detached HEAD 的工作树:
git worktree add --detach ../shop-check v2.3.0
Detached HEAD 的中文直觉是“当前指向一个提交,而不是跟着某个分支名”。可以查看和试验;若产生了值得保留的提交,记得及时创建分支。
工作与汇合仍然使用普通 Git
进入新目录以后,修改、暂存、提交、推送都和平时一样:
cd ../shop-hotfix
npm test
git add src/payment.ts tests/payment.test.ts
git commit -m "fix: restore payment submission"
Worktree 没有发明新的合并方式。任务完成后,仍然通过 pull request、merge、rebase 或 cherry-pick 把结果带回目标分支。它改变的是工作发生在哪里,不是历史如何组合。
用 Git 删除,不要直接拖进废纸篓
完成后运行:
git worktree remove ../shop-hotfix
git branch -d hotfix/payment
第一条删除关联工作目录,第二条按需删除已经合并的分支。Git 会拒绝直接移除含有未提交改动的 worktree,这是有意设置的保护。
若你已经手工删除了目录,仓库里可能留下失效记录。先预览,再清理:
git worktree prune --dry-run
git worktree prune
移动了主仓库或关联目录,导致连接失效时,优先使用 git worktree repair,不要手工猜测 .git/worktrees/ 中的内部文件。
--force 会越过“分支已被其他 worktree 使用”或“工作树不干净”等保护。遇到拒绝时,先运行 git worktree list 和目标目录里的 git status 理解原因。多数情况下,修正分支选择或提交现场比强行绕过更安全。
一次可复述的路径是:先列清单,再从明确基线创建;独立完成并提交;用普通分支流程汇合;确认干净后由 Git 清理目录。
五、Agent 时代重新发现了 Worktree
人独自写代码时,常见节奏是一次专注一项工作。登录页没写完,支付热修只能插队。Worktree 能减少切换成本,但很多人并不经常需要两张同时活跃的工作台,因此它长期像一个“知道很好、偶尔才用”的工具。
Coding Agent 改变了瓶颈。生成和修改代码的执行者突然可以同时有多个:一个实现登录页,一个修支付问题,一个升级依赖。此时限制并行度的,不再只是人的手速,而是它们能不能同时写同一个仓库而不踩乱彼此的文件现场。
下面保持三个任务完全相同,只切换“共用一个目录”与“每个任务一棵 worktree”。
AGENT CONCURRENCY LAB
目录数量怎样改变并行方式
正在修改 src/auth.ts
需要 A 先提交或 stash
切分支会覆盖眼前文件
wt-login → agent/login
wt-hotfix → agent/payment
wt-deps → agent/deps
简化模型:它展示文件隔离,不代表任务一定能安全并行。两个 Agent 即使在不同目录修改同一段逻辑,合并时仍可能冲突。
如果三个 Agent 共用一个目录,即使它们声称各自在不同分支上工作,进程看到的仍是同一组文件和同一个 index。A 切分支会改变 B 正在读取的文件;B 暂存文件可能把 C 的改动带进提交;一个 Agent 运行格式化,也可能重写另一个 Agent 正在编辑的文件。为了安全,它们只能排队,或者依赖非常脆弱的协作约定。
一任务一 worktree 后,每个 Agent 得到:
- 一个稳定的起始提交;
- 一个独立分支;
- 一套独立的源文件与暂存区;
- 可以单独检查、测试和丢弃的 diff。
这也是为什么当代 Agent 工具越来越常把 worktree 当成会话隔离单元。GitHub 在介绍并行 Agent 会话时,也明确把“每个会话位于自己的 worktree 和分支”作为文件、对话与任务状态隔离的基础; GitHub Desktop 的 worktree 支持 同样把 Agent 并行列为直接使用场景。
这里发生的不是 worktree 本质改变了,而是生产关系变了:以前它让一个人不必收拾上一张桌子;现在它让多个执行者同时拥有各自的桌子。
六、Vibe Coding 中更重要的是可审阅的边界
Vibe coding 常把需求表达、实现选择和大量文件修改压缩进一次对话。速度上升后,新的成本会落在监督:哪一个 Agent 改了什么,它从哪里出发,结果能不能独立测试,不满意时能不能完整丢弃。
Worktree 在这里提供的价值不只是“更快”,还有一条清楚的责任边界:
任务描述
↓
起始提交 + 独立分支 + 独立 worktree
↓
Agent 修改、测试、提交
↓
人查看 diff 与验证结果
↓
合并 / 要求返工 / 整棵丢弃
当一次实验失败,你可以删除它的 worktree 和分支,而不用从混杂的主目录中辨认哪些文件属于谁。当两个 Agent 给出不同方案,你也可以分别启动应用、比较 diff 和测试结果,再选择其一。这让“让 Agent 试试看”从不可控的直接改写,变成一个有入口、有出口的实验单元。
一个实用的任务命名方式
假设仓库是 shop,可以把 Agent 工作树集中放在相邻目录:
projects/
├── shop/ # main,人负责汇合与最终验证
├── shop-wt-login/ # agent/login
├── shop-wt-payment/ # agent/payment-hotfix
└── shop-wt-deps/ # agent/deps-upgrade
分支和目录都带上短任务名,目的是让 git worktree list 的结果一眼可读。目录不必使用 wt,分支也不必使用 agent/;稳定一致比具体格式重要。
给 Agent 的任务边界至少可以包含:
只在当前 worktree 内修改。
从当前分支开始,不切换或重置其他分支。
不要改写 worktree 之外的文件。
完成后运行指定测试,提交变更,并总结风险与未完成项。
不要合并到 main;等待人工评审。
这些约束不是因为 worktree 不可靠,而是因为它只负责文件现场。Agent 是否选对方案、是否修改了外部服务、是否擅自扩大范围,仍要靠任务说明、权限和评审控制。
并行之前先检查任务是否真的独立
能创建三棵 worktree,不代表三项任务适合并行。可以先看它们可能触碰的边界:
| 任务关系 | 并行建议 | 原因 |
|---|---|---|
| 修改互不相干的模块 | 很适合 | 文件和语义交叉少 |
| 一个写功能,一个补独立文档 | 通常适合 | 汇合成本较低 |
| 同时改同一份依赖锁文件 | 谨慎 | 文本冲突概率高 |
| 同时迁移同一数据库 schema | 不宜直接并行 | 外部状态和顺序依赖强 |
| B 必须依赖 A 新增的接口 | 先 A 后 B,或明确基线 | B 的起始版本缺少必要前提 |
Worktree 把执行冲突推迟成更容易看见的集成冲突,却不会让冲突凭空消失。这已经很有价值:文件不会在生成过程中互相覆盖,失败也局限在单个目录。但最终仍需有人决定多个正确的局部修改能否组成正确的系统。
七、并行工作最常见的六个坑
起点过旧
Agent 从昨天的 main 建立 worktree,今天完成时主线已经前进很远。隔离没有问题,集成成本却被拖到最后。长任务应定期明确是否需要 fetch、rebase 或重新建立基线,更新前先确认工作区状态。
两个任务改同一片语义
Git 只能检测部分文本冲突。A 改了折扣计算,B 在另一个文件里改变了税费顺序,即使自动合并没有冲突,组合后的业务含义也可能错。这叫语义冲突,必须靠测试、评审和系统理解发现。
共享端口与数据库
三个 worktree 同时执行 npm run dev,都监听 3000,后启动的进程会失败。更危险的是共用开发数据库:一个 Agent 迁移 schema,另一个的测试数据随之变化。为每项任务分配端口、数据库名称或临时环境,才是完整并行方案。
依赖占用大量空间
Git 对象库共享,不代表 node_modules、构建产物和缓存一定共享。多个大型 worktree 可能迅速占满磁盘。包管理器的全局内容寻址缓存可以减少下载,但每个项目目录仍可能产生链接、构建缓存和输出文件。
把关联目录放进仓库内部
若把 worktree 建在主目录的未忽略子目录里,主 worktree 可能把整个关联目录视为未跟踪内容。更稳妥的默认选择是相邻目录,例如 ../shop-wt-login;若团队采用仓库内部的统一目录,则必须先设计好忽略规则和工具兼容性。
清目录却忘了清记录
手工删除文件夹可能留下 prunable 记录;长时间保留的临时 worktree 又会让分支和目录清单越来越难读。把 git worktree list、remove 和 prune --dry-run 纳入日常收尾,比偶尔进行一次大扫除可靠。
此外,Git 当前官方文档仍提醒:多工作树与 submodule 的组合支持并不完整,不建议对包含 submodule 的超级项目随意做多个 checkout。遇到这类仓库,应先在小范围验证真实行为,而不是假设每个依赖都会自然隔离。完整命令与最新限制以 git-worktree 官方文档 为准。
八、从热修工具到并行调度原语
现在回放整条路径。
最初的问题是:一个 Git 仓库的分支很轻,但一个工作目录只能呈现一个文件现场。人们先用额外脚本和符号链接连接多个目录;Git 2.5 把这件事变成仓库明确知道、能够管理的 linked worktree。它首先服务于很传统的场景:开发中途处理热修、同时测试另一个版本、保留一个长期构建目录。
Agent 时代没有改写这个机制,只把它的价值放大了:
共同仓库 → 为每项任务创建独立分支与 worktree → 多个 Agent 分别修改和测试 → 通过 diff、提交与测试评审 → 再把结果汇合到主线
这条链路里,worktree 做了两件很具体的事:让并行写文件成为可能,让每项变化可以单独审阅和丢弃。它没有替你拆分任务,没有判断代码对错,也没有隔离端口、数据库和云端资源。
因此,在 vibe coding 中使用 worktree,最稳妥的心态不是“终于可以无限开 Agent”,而是:
给每个并行实验一张独立工作台、一个明确起点和一条独立分支;完成后再把人的注意力放在差异、验证与汇合上。
Worktree 出生时解决的是“不要为了一个热修毁掉手头现场”。到了 Agent 时代,它承担的是同一个更大版本的问题:不要让更多执行者共享一个混乱现场。
延伸阅读
-
Git 2.5 Release Notes :worktree 正式进入 Git 时的发布说明。
-
git-worktree 官方文档 :当前命令、配置、内部结构与限制。
-
Git repository layout :理解
$GIT_DIR/worktrees与共享仓库布局。 -
GitHub:What are Git worktrees, and why should I use them? :worktree 在现代并行与 Agent 工作流中的实际位置。