TECH
用 Git Worktree 跑并行任务:AI Coding 场景下的隔离、协作与收尾
解释 Git Worktree 在 AI Coding 中的真正角色:什么时候该开独立工位,什么时候没必要开,以及任务结束后如何合并分支、删除旧 worktree 与清理残留。
修订记录
| 版本 | 时间 | 说明 |
|---|---|---|
| v1 | 2026-03-06 | 初稿:从 README 迁出 worktree 内容,重写为 AI Coding 并行任务指南 |
Why:为什么 AI Coding 特别需要 worktree
单人开发时代,很多人对分支已经够用了:切到 feat/a 做一会儿,再切回 main 修一个小问题,忍一忍也能做完。
但在 AI Coding 场景里,真正稀缺的往往不是“能不能切分支”,而是下面三件事:
- 会话边界是否清晰。
- 当前工作区是否干净。
- 两个任务能不能并行推进,而不是互相打断。
一旦开始用 AI 同时推进两个任务,问题就不一样了。真正麻烦的往往不是 Git 命令本身,而是下面这些现场会缠在一起:
- 当前目录已经改到一半,又插进来一个紧急 bug。
- 一个 AI 会话还占着现有上下文,另一个任务却已经要开始。
- 同一个工作目录里来回切分支,很容易把未完成改动、终端状态和会话目标搅在一起。
这时候,git worktree 才显出价值:给每个任务一个独立目录、一个独立分支、一个独立会话。这样做最直接的收益,是少做很多来回切换和收拾现场的动作。
所以这篇文章真正想解决的,是当手头有两个任务同时推进时,怎样把分支、目录和会话拆开,避免互相污染。命令只是其中一部分。
What:worktree 到底是什么,它又不是什么
一句话说,git worktree 就是给同一个仓库开多个独立工位。
可以把它理解成:
- 分支负责表达“代码历史和变更主题”。
- worktree 负责表达“今天在哪个物理工作区里干活”。
所以它不是分支的替代品,而是分支的工作区载体。
这也能解释一个常见困惑:为什么有时候会用 worktree,有时候又不会?
原因很简单,worktree 不是必须步骤,而是“需要隔离时才启用”的能力。以下几种情况,通常值得开:
- 当前工作区已经有未完成改动,但又要插入第二个任务。
- 两个任务改动面不同,想拆成两个独立提交或两个独立评审单元。
- 希望给不同 AI 会话明确边界,避免上下文串味。
- 需要同时打开两个分支做比对、验证或回归。
反过来,以下情况通常没必要:
- 当前仓库很干净,只做一个线性任务。
- 只是改一两个文件的小修复,十分钟内能收口。
- 两个改动强耦合,本质上就是同一条变更链。
再回答一个更贴近实际的问题:在 VS Code + Codex + superpowers 这类工作流里,worktree 是自动的吗?
结论是:Git 本身不会自动替你创建 worktree;是否使用,取决于当前工作流有没有显式选择“隔离工作区”这条路径。
以这套工作流为例,可以把它理解成三层:
- Git 能力层:只有执行了
git worktree add ...,新的 worktree 才真的存在。 - Agent 工作流层:某些 skill 或流程会建议在开始 feature、执行 plan、需要隔离时创建 worktree;没有走到这一步,就继续在当前目录工作。
- 个人操作层:如果明确知道任务要并行、要分会话、要防污染,最好在任务开始前主动决定是否开新工位。
所以它不是某个“一次开启、永久生效”的全局开关,而更像是每次启动任务时做的一次工作方式选择。
How:如何用 worktree 支撑多个任务并行跑
下面给一条最小可用路径,适合日常 AI Coding。
第一步:先判断任务是否真的适合并行
最适合拆成两个 worktree 的,一般是这类组合:
- 任务 A:后端接口、脚本、数据迁移一类的主线改动。
- 任务 B:E2E、文档、回归验证、样式修补这类旁路改动。
判断标准不是“能不能并行”,而是“并行后会不会互相踩”。如果两个任务高度依赖同一批未完成代码,那么最好还是顺序推进。
第二步:一个任务,一个分支,一个 worktree
先看已有工位:
git worktree list
然后创建新工位。下面以项目内隐藏目录 .worktrees/ 为例:
mkdir -p .worktrees
git worktree add .worktrees/feat-api-refactor -b feat/api-refactor
git worktree add .worktrees/feat-e2e-stability -b feat/e2e-stability
如果团队不希望在仓库内放 .worktrees/,也可以放到仓库同级目录:
git worktree add ../project-feat-api-refactor -b feat/api-refactor
有两个注意点:
- 如果使用
.worktrees/这类项目内目录,应该先确认它被.gitignore忽略。 - 同一个分支不能同时检出到两个 worktree;Git 默认会拒绝这种操作。
第三步:一个窗口一个会话,不要混跑
创建好工位后,真正稳定的做法不是“有了两个目录就算完成”,而是继续把执行面拆开:
- 一个 worktree 对应一个 VS Code 窗口。
- 一个 worktree 对应一个终端上下文。
- 一个 worktree 对应一段独立的 Codex 或 Agent 会话。
这样做的好处是,任务 A 的上下文不会污染任务 B。对于 AI 工具来说,这一步比“会不会用 Git 命令”更重要。
第四步:各自开发,各自提交
在每个工位中独立完成改动、测试和提交。例如:
cd .worktrees/feat-api-refactor
git status
git add .
git commit -m "feat: refactor api workflow"
这里最容易写错的一点是:提交完成,不代表 worktree 生命周期结束。
提交只是形成了一个清晰 checkpoint,方便评审、回滚、继续迭代。只要这个工位还承担后续任务,就可以继续保留。
但还有一个同样重要的事实:在 worktree 里 commit,只是把改动提交到了这个 worktree 对应的分支上,不会自动进入 main。
如果目标是“把结果交回主分支”,后面仍然要走一次合并动作。常见方式有三种:
git mergegit rebase后快进合入git cherry-pick
无论选哪种,核心都一样:commit 解决的是“先把改动记在分支上”,merge 解决的是“让主分支真正拿到这次改动”。
第五步:任务结束后再决定“留还是删”
真正应该问的不是“我已经 commit 了,要不要删 worktree”,而是:
- 这个分支后面还要继续改吗?
- 这个改动已经进入评审或合并流程了吗?
- 我还需要保留这个目录作为独立上下文吗?
常见收尾路径如下:
- 还要继续改:保留 worktree。
- 已经合并完成、后面没后续:删除 worktree。
- 暂时中断,但过几天还要回来:可以保留 worktree,不必急着清。
Principles:什么时候该用,什么时候没必要用
经验上,可以把 worktree 当成一种“高价值隔离工具”,而不是默认动作。
适合使用的场景
- 当前目录有未提交改动,又来了一个插队任务。
- 需要把两项任务拆成两个独立 PR 或两个独立评审批次。
- AI 会话已经很长,希望给新任务一个干净上下文。
- 需要对两个分支同时做运行、对比或回归。
不必强行使用的场景
- 任务很小,当前分支也很干净。
- 两个改动本质上属于同一次提交。
- 团队当前流程更依赖快速收口,而不是长期并行。
三个容易混淆的点
-
worktree != branch分支是历史线,worktree 是工位。 -
删 worktree != 删分支git worktree remove只移除工位和对应元数据,不会自动删除分支。 -
commit != worktree 结束commit 是里程碑,不是工位的死亡时间。
如果只记一条原则,可以记这句:worktree 的生命周期,跟任务生命周期走,而不是跟某一次 commit 走。
Operations:任务跑完后,状态是什么,该怎么处理
这部分专门回答日常使用中最容易卡住的问题。
场景 1:任务做完了,但还没合并
这时最正常的状态就是:
- worktree 还在。
- 分支还在。
- 改动已经提交,等待 code review 或等待与主线对齐。
这不是脏状态,而是一个很正常的“待合并”状态。
这里最容易混淆的一点是:此时 main 还没有这些代码。
因为提交发生在 feat/... 分支上,不发生在 main 上。只要还没 merge、rebase 或 cherry-pick 回主线,主分支就看不到这次结果。
场景 2:只删 worktree,不合主分支,会发生什么
需要分两种情况看:
- 如果只是删除 worktree,但分支还在,代码通常不会立刻丢,因为提交还挂在那个分支上;只是
main依然看不到。 - 如果 worktree 删了,分支也删了,而且这些提交没有被别的分支引用,那这条改动线才会有真正丢失风险。
所以,“删工位”不等于“把结果交回主线”。如果目标是把结果留在主分支,合并这一步不是可选项,而是交付动作本身。
场景 3:任务已经合并完成,准备清理
推荐顺序如下:
# 回到主工作区或任一正常工作区
git switch main
git pull --ff-only
git merge --no-ff feat/api-refactor
# 删除已经合并的分支
git branch -d feat/api-refactor
# 删除对应工位
git worktree remove .worktrees/feat-api-refactor
如果团队走 PR 流程,也可以把“合并”这一步放到 GitHub、GitLab 或其他托管平台完成。平台合并后,本地再做两件事:
git switch main
git fetch --all --prune
git branch -d feat/api-refactor
git worktree remove .worktrees/feat-api-refactor
场景 4:想直接删工位,但里面还有未提交改动
默认不行。git worktree remove 只允许删除干净的 worktree。
如果目录里还有已修改或未跟踪文件,Git 会拒绝删除。只有在你非常确定这些改动不要了时,才考虑:
git worktree remove --force .worktrees/feat-api-refactor
建议把 --force 理解成“放弃这个工位里的未收口现场”,而不是普通清理命令。
场景 5:目录被手工删掉了,Git 里还挂着记录
这时常见现象是 git worktree list 里还能看到一个已经不存在的路径,通常会标成 prunable。
清理方式:
git worktree prune
这一步清的是仓库里的 worktree 管理元数据,不是删除真实代码文件。
场景 6:仓库挪位置了,worktree 记录失联
如果主仓库或 linked worktree 被手工移动,路径关系可能失效。这时可以尝试:
git worktree repair
这个命令的作用是重建主仓库与 linked worktree 之间的管理连接。
一套可复用的最小工作流
如果希望把这件事变成团队可执行习惯,可以直接采用下面这条规则:
- 一个独立任务,对应一个分支。
- 一个独立任务,如果需要并行或隔离,再对应一个 worktree。
- 一个独立 worktree,对应一个 VS Code 窗口和一段 AI 会话。
- 合并完成后,再决定是否删分支、删 worktree。
这样,worktree 就不再是“偶尔才想起的 Git 冷门命令”,而会变成 AI Coding 时代一套很实用的并行协作手法。
结语
很多关于 worktree 的困惑,本质上都不是命令问题,而是工作流边界问题:
- 什么时候需要隔离?
- 隔离的是代码,还是会话,还是验证环境?
- 隔离结束后,哪些东西该保留,哪些东西该清理?
把这三个问题想清楚,worktree 就会从“看起来很高级的小技巧”,变成一套可持续复用的任务编排工具。
评论