1. 单会话串行到底卡在哪里
用 Claude Code 写代码的人,大概都经历过这种节奏:一个会话里让它改 A 模块,等它读完文件、想完、写完,再让它改 B 模块,再等一轮。中间你只能干看着,或者切出去刷会儿别的。一天下来,真正推进的事情没几件,时间全耗在"等 AI 想"上了。
这个瓶颈的本质不是模型慢,而是会话是串行的。一个 Claude Code 会话在任意时刻只能处理一个任务流,它的上下文、它的工具调用、它的文件读写,全都绑在这一条线上。你让它同时干三件事,它做不到——它只会一件一件来。
那"一个人干三个人的活"是怎么实现的?答案不是让单个会话变快,而是同时开多个会话,每个会话负责一条独立的工作线。这就像你从"一个人排队办事"变成"开三个窗口同时办事"。窗口之间互不干扰,各自推进,你只需要在它们之间做调度。
但这里有个绕不开的问题:多个会话如果都在同一个工作目录里改文件,会互相踩踏。A 会话正在改utils.py,B 会话也去改utils.py,两边一保存,冲突就来了。所以并行多会话的前提,是每个会话有自己独立的工作副本。这就是 Git Worktree 出场的地方。
下面我会把整套东西拆开讲:为什么是 Worktree 而不是别的方案、怎么把环境搭起来、多个会话怎么分工、实际跑起来会遇到哪些坑。内容偏实操,假设你已经装好了 Claude Code,也对 Git 有基本概念。
2. 为什么是 Git Worktree,而不是复制目录或另开分支
先说结论:并行多会话的物理基础是"每个会话一个独立工作目录",而 Git Worktree 是目前最干净的实现方式。但很多人第一反应不是 Worktree,而是"我复制一份项目目录不就行了",或者"我开个新分支不就行了"。这两种做法都能跑,但都有硬伤,值得掰开说。
2.1 复制目录方案:简单但会埋雷
复制整个项目目录,最直观。cp -r project project-b,然后在project-b里开第二个会话。听起来没问题,但实际用起来有几个坑。
第一,依赖和构建产物会重复。一个中等规模的 Node 项目,node_modules动辄几百 MB 到几个 GB。复制一份,磁盘直接翻倍。Python 项目的虚拟环境、Java 项目的target目录,同理。你要是开三个会话,就是三份依赖,磁盘和内存都吃不消。
第二,Git 状态是割裂的。复制出来的目录,它的.git是独立的一份,和原目录没有关联。你在副本里提交的代码,原目录看不到;你想把副本的改动合并回去,得手动git remote add或者干脆复制文件。这就失去了版本控制的意义。
第三,容易忘记清理。临时复制的目录,用完经常忘了删,越积越多,最后自己都分不清哪个是哪个。
2.2 另开分支方案:共享目录,必然打架
"我开个新分支不就行了"——这个思路的问题在于,分支切换是全局的。Git 的分支是绑在工作目录上的,你git checkout feature-b,整个工作目录就切到 feature-b 了。这时候你原来的会话还在跑,它读到的文件已经变成另一个分支的内容了。
换句话说,同一个工作目录,同一时刻只能处于一个分支。你想让两个会话同时工作在两个分支上,物理上做不到。除非你不停地切来切去,但那样两个会话都会读到错乱的文件状态,比串行还糟。
2.3 Worktree 方案:一个仓库,多个工作目录
Git Worktree 解决的正是这个问题。它允许同一个 Git 仓库挂载出多个工作目录,每个目录可以 checkout 不同的分支。这些目录共享同一个.git对象库,所以:
- 磁盘上不重复存储历史对象,只多出工作区的文件;
- 每个 worktree 有独立的分支、独立的暂存区、独立的工作状态;
- 在任意一个 worktree 里的提交,其他 worktree 都能通过 Git 看到。
用一句话概括:Worktree 让你用一份仓库的代价,换来多个互不干扰的工作现场。这正好对应并行多会话的需求——每个会话一个 worktree,各改各的,互不踩踏。
| 方案 | 磁盘开销 | Git 状态 | 会话隔离 | 合并回主线的难度 |
|---|---|---|---|---|
| 复制目录 | 高(依赖重复) | 割裂,需手动同步 | 好 | 高 |
| 另开分支 | 低 | 共享但会互相切换 | 差(同一目录) | 低 |
| Git Worktree | 低(共享对象库) | 共享且各自独立 | 好 | 低 |
从表里能看出来,Worktree 是唯一同时满足"低开销 + 好隔离 + 易合并"的方案。这也是为什么现在聊 Claude Code 并行多会话,几乎都会提到 Git Worktree。
提示:Worktree 不是新东西,Git 2.5 就有了,只是一直不温不火。它真正被大规模用起来,恰恰是因为 AI 编程助手需要"多个独立工作现场"这个场景。
3. 把并行环境搭起来:从安装到第一个 Worktree
这一节讲具体怎么落地。假设你已经在用 Claude Code,Git 也装好了。如果你还没装 Claude Code,先把它装上——不同系统的安装方式不一样,装完之后确认claude命令能在终端里跑起来,这是后面所有操作的前提。
3.1 确认 Git 版本和基础配置
Worktree 需要 Git 2.5 以上,现在基本都满足。先确认一下:
git --version然后确认你的主仓库是干净的,没有未提交的改动。这点很重要,因为 Worktree 是从当前仓库状态派生的,如果主目录一团乱,派生出来的 worktree 也会带着问题。
git status如果有未提交的改动,先提交或者 stash 掉。我个人的习惯是,在开并行会话之前,先把主分支整理干净,这样每个 worktree 都有一个明确的起点。
3.2 创建第一个 Worktree
假设你的项目在~/projects/myapp,你想开一条新工作线做"用户认证模块重构"。先建一个分支,再基于它建 worktree:
cd ~/projects/myapp git worktree add ../myapp-auth -b feature/auth-refactor这条命令做了两件事:创建一个新分支feature/auth-refactor,并在../myapp-auth目录里把它 checkout 出来。现在~/projects/myapp-auth就是一个独立的工作目录,和主目录共享同一个.git。
进去看看:
cd ../myapp-auth git branch你会看到当前在feature/auth-refactor上。在这个目录里改任何东西,都不会影响主目录。
3.3 在 Worktree 里启动 Claude Code
这是关键一步。每个 worktree 目录里,单独启动一个 Claude Code 会话:
cd ~/projects/myapp-auth claude现在这个会话的所有文件操作,都局限在myapp-auth这个目录里。你再开一个终端,进另一个 worktree,启动第二个会话,两个会话就完全隔离了。
我一般会开三个终端窗口,或者用 tmux 分屏,每个窗口对应一个 worktree。这样一眼就能看到三个会话各自在干什么。
3.4 查看和管理所有 Worktree
Worktree 多了之后,需要能随时看到全貌:
git worktree list输出大概是这样:
~/projects/myapp abc1234 [main] ~/projects/myapp-auth def5678 [feature/auth-refactor] ~/projects/myapp-api ghi9012 [feature/api-redesign]用完的 worktree 要记得清理,否则会越积越多:
git worktree remove ../myapp-auth如果这个 worktree 里还有未提交的改动,remove会拒绝执行,防止你误删。确认不要了,可以加--force。分支本身不会因为 worktree 删除而消失,需要的话再单独git branch -d。
注意:删除 worktree 之前,务必确认里面的改动已经提交或者合并。我踩过一次坑,一个 worktree 里改了半天没提交,直接 remove 掉了,虽然理论上能从 Git 对象里捞回来,但过程很折腾。养成"离开 worktree 前先 commit"的习惯。
4. 多会话怎么分工:三条并行的真实工作线
环境搭好了,接下来是更实际的问题:三个会话到底怎么分工,才能真的"干三个人的活"。不是随便开三个会话就叫并行,分工不合理,反而会互相制造麻烦。下面用三个典型场景说明。
4.1 场景一:功能开发 + 测试编写 + 文档更新
这是最经典的三线并行。假设你要做一个新功能"订单导出":
- 会话 A(功能线):在
myapp-featureworktree 里,让 Claude Code 实现导出逻辑,改业务代码。 - 会话 B(测试线):在
myapp-testworktree 里,基于功能线的接口约定,写单元测试和集成测试。 - 会话 C(文档线):在
myapp-docsworktree 里,更新 API 文档和使用说明。
这三条线的依赖关系是:测试和文档都依赖功能线的接口定义。所以开工前要先约定好接口——函数签名、参数、返回值。约定好了,三条线就能真正并行;没约定好,测试线写出来的测试对不上功能线的实现,最后还得返工。
我的做法是,先在主目录里花十分钟把接口定义写成一个简单的 markdown 或者注释,然后三个 worktree 都基于这个约定开工。这十分钟的投入,能省掉后面大量的对齐成本。
4.2 场景二:主分支修 bug + 分支做重构
有时候你手上有个紧急 bug 要修,同时又在推进一个大重构。这两件事如果在一个会话里做,上下文会互相污染——重构的改动还没稳定,修 bug 时读到的代码可能是半成品。
用 Worktree 就清爽了:
- 会话 A:主目录(
main分支),专门修紧急 bug,改完直接提交、推送。 - 会话 B:
myapp-refactorworktree,慢慢做重构,不受 bug 修复的干扰。
这样紧急 bug 的修复可以快速上线,重构线继续按自己的节奏走。等重构完成,再合并回主分支。
4.3 场景三:同一功能的多方案对比
这个场景比较进阶,但很实用。有时候你不确定某个功能该怎么实现,想试试两种不同的技术方案。传统做法是试完 A 再试 B,串行对比。用 Worktree 可以同时试:
- 会话 A:
myapp-approach-aworktree,用方案 A 实现。 - 会话 B:
myapp-approach-bworktree,用方案 B 实现。
两个会话同时跑,跑完你直接对比两边的代码和效果,选好的那个合并。这比串行试快一倍,而且对比更直观——两边的代码都还在,随时能翻。
| 场景 | 会话 A | 会话 B | 会话 C | 关键前提 |
|---|---|---|---|---|
| 功能开发 | 业务代码 | 测试代码 | 文档 | 先约定接口 |
| 修 bug + 重构 | 主分支修 bug | 分支重构 | — | 分支独立 |
| 多方案对比 | 方案 A | 方案 B | — | 目标明确 |
4.4 分工的核心原则:减少跨会话依赖
不管哪种场景,分工的核心原则都是一条:尽量让每个会话的工作自包含,减少跨会话的依赖。
依赖越少,并行度越高。如果会话 A 的每一步都要等会话 B 的输出,那本质上还是串行,只是换了个形式。真正高效的并行,是三条线各自能独立推进,只在关键节点做一次对齐。
我一般会在开工前画一个简单的依赖图(脑子里过一遍就行):哪些是独立的,哪些有先后。独立的并行,有先后的串行或者先约定接口再并行。
5. 实测中绕不开的坑:冲突、上下文与资源
并行多会话听起来很美,但实际跑起来,有几个坑几乎一定会遇到。这一节把踩过的坑和排查过程完整写出来,方便你复现排查思路。
5.1 合并冲突:并行改动的必然代价
只要多个会话改了同一批文件,合并时就会有冲突。这不是 Worktree 的问题,是并行开发的固有代价。Worktree 只是让冲突在合并时暴露,而不是在编辑时互相覆盖。
排查和处理的思路:
- 先看冲突范围。
git merge feature/auth-refactor之后,git status会列出冲突文件。 - 判断冲突类型。如果是同一函数的不同实现,需要人工决策保留哪个;如果是格式差异(比如缩进、换行),可以用工具自动处理。
- 优先在 worktree 里解决。我习惯在 worktree 里先
git rebase main,把主分支的最新改动拉进来,在 worktree 里解决冲突,解决完再合并回主分支。这样主分支始终保持干净。
减少冲突的根本办法,还是分工时尽量让不同会话改不同的文件。如果两个会话注定要改同一个文件,那就要么串行,要么提前约定好各自改哪部分。
5.2 上下文隔离:每个会话都是"失忆"的
这是很多人忽略的一点。每个 Claude Code 会话的上下文是独立的。会话 A 里你跟它聊了半天的项目背景、架构决策,会话 B 完全不知道。
这意味着,如果你在会话 A 里让 Claude Code 理解了某个复杂的设计意图,然后切到会话 B 让它做相关的事,你得重新把背景讲一遍。否则会话 B 会基于它自己读到的代码做判断,可能和会话 A 的决策不一致。
我的应对办法是,把重要的项目背景和约定写成一个文件,比如PROJECT_CONTEXT.md,放在仓库里。每个会话开工前,先让它读这个文件。这样背景只需要维护一份,所有会话共享。
# 在每个 worktree 的会话里,第一件事 > 先读一下项目根目录的 PROJECT_CONTEXT.md,了解当前的架构约定5.3 资源占用:三个会话不等于三倍开销
开三个会话,内存和 CPU 占用会上升,但不是简单的三倍。Claude Code 本身是个客户端,主要的计算在服务端,本地占用主要是文件监听和一些辅助进程。真正吃资源的是每个 worktree 的依赖和构建。
如果你在三个 worktree 里都跑了npm install,那就是三份node_modules。这时候磁盘和内存的压力就上来了。我的做法是:
- 能用软链接共享的依赖就共享(比如把
node_modules软链到主目录的); - 构建产物按需生成,不用的 worktree 不跑构建;
- 定期清理不用的 worktree。
提示:软链接共享依赖有风险,如果不同分支的依赖版本不同,会出问题。只在确认依赖一致时用。
5.4 会话"跑飞":如何及时发现和止损
并行跑三个会话,最大的风险是某个会话跑偏了你还不知道。比如会话 B 理解错了需求,写了一堆没用的代码,等你发现时已经改了很多文件。
我的做法是定期巡检。每隔一段时间,切到每个 worktree 看一眼git diff,确认改动方向是对的。发现跑偏,立刻在那个会话里纠正,别等它跑完。
# 在 worktree 里快速看改动概况 git diff --stat如果改动量异常大,或者改的文件不在预期范围内,就要警惕了。
6. 让并行真正提速的几个实操技巧
前面讲了原理和坑,这一节分享几个让并行多会话真正跑出效率的技巧。这些是我用下来觉得最有价值的,常规文档里不太会写。
6.1 用 tmux 或分屏管理多个会话
开三个终端窗口来回切,效率很低。用 tmux 分屏,三个会话并排显示,一眼看全:
tmux new-session -s claude-parallel # 然后 Ctrl+b % 垂直分屏,Ctrl+b " 水平分屏每个 pane 里进一个 worktree,启动一个 Claude Code。这样你随时能看到三个会话的状态,哪个在等你输入,哪个在跑,一目了然。
6.2 给每个 worktree 起有意义的名字
myapp-1、myapp-2这种名字,过两天你自己都忘了哪个是哪个。用任务相关的名字:myapp-auth、myapp-api、myapp-docs。分支名也一样,feature/auth-refactor比feature/branch1清楚得多。
6.3 主分支保持"随时可发布"状态
并行开发时,主分支很容易被各种半成品污染。我的原则是:主分支永远保持可发布状态。所有实验性的、未完成的工作,都在 worktree 的分支里做。只有确认完成、测试通过的功能,才合并回主分支。
这样即使并行线出了问题,主分支也不受影响,随时能发版。
6.4 定期同步主分支到各 worktree
并行跑久了,各 worktree 会落后于主分支。定期把主分支的最新改动同步进来,能减少最后合并时的冲突量:
# 在 worktree 里 git fetch origin git rebase origin/main我一般每天开工前做一次同步,让所有工作线都基于最新的主分支。
6.5 别贪多,两到三条线是甜点区
理论上你可以开十个 worktree、十个会话。但实际用下来,两到三条并行线是效率最高的。超过三条,你的注意力会被分散,巡检成本上升,反而容易出错。
人的精力是有限的。三个会话同时跑,你还能跟得上每个的进度;五个以上,你就只能被动地等它们报错,失去了"调度"的意义。所以别追求数量,追求的是每条线都能被你有效管理。
7. 从串行到并行,真正改变的是什么
用了一段时间并行多会话之后,我最大的感受不是"快了多少倍",而是工作方式变了。
以前串行的时候,我的节奏是被 AI 带着走的——它想的时候我等着,它写完我看一眼,再给下一个指令。一天下来,我更像一个"监工",盯着一个工人干活。
并行之后,我变成了"调度者"。三个会话各自推进,我的工作是分配任务、巡检进度、处理冲突、做关键决策。等待的时间被填满了——会话 A 在跑的时候,我去看会话 B 的产出,或者给会话 C 补充背景。
这种转变的前提,是你得提前想清楚要做什么。串行的时候可以走一步看一步,并行的时候不行——三条线同时开工,你必须先把任务拆清楚、接口约定好,否则就是三倍的混乱。
所以并行多会话真正考验的,不是工具用得多熟,而是你能不能把一个任务拆成几条独立的工作线。这个能力,比任何工具配置都重要。工具只是放大器,拆得好,它放大效率;拆不好,它放大混乱。
最后分享一个我自己的习惯:每次开并行会话之前,花五分钟在纸上或者文档里写下三条线各自要做什么、依赖什么、预期产出是什么。这五分钟的规划,决定了接下来几个小时是高效推进还是反复返工。