Cursor 2.0 多 Agent 模式使用的 Git Worktree 原理、实战与避坑指南
最近在看 Cursor 2.0 的新功能,发现它的多 agent 模式用了 git worktree 来实现并行任务。当时看到这个的时候我有点懵,因为虽然平时用 Git 用得挺多,但 worktree 这个指令我真的了解不多,甚至都不太确定它具体是干什么的。
后来专门去查了一下,发现这东西其实挺有意思的。说白了,worktree 就是让你在同一个 Git 仓库里同时维护多个工作目录,每个目录可以检出不同的分支或者提交。听起来好像有点抽象,但如果你遇到过下面这种情况,就能理解它解决的是什么问题了。
比如你正在开发一个新功能,代码写了一半,突然产品经理跑过来说线上有个紧急 bug 要修。传统做法是什么?要么把当前改动 stash 起来,切到 master 分支去修 bug,修完再切回来把 stash pop 出来继续干活。要么就是再 clone 一个仓库出来专门修 bug。

第一种方案看起来还行,但如果你 stash 的次数多了,有时候会忘记之前 stash 了什么,甚至不小心把 stash 弄丢了。而且来回切分支的时候,IDE 要重新索引,编译环境要重新配置,这些都挺烦的。
worktree 就是在这种情况下派上用场的。它让你可以基于同一个仓库创建多个独立的工作目录,这些目录共享底层的 .git/objects,但各自有独立的 HEAD、index 和工作区文件。

我第一次用的时候是这样的。正在开发 feature/login 分支,突然要修 release/1.5 的一个 bug。我没有切分支,而是直接在项目根目录下创建了一个新的 worktree:
git worktree add../hotfix-1.5 release/1.5 这个命令会在上级目录创建一个 hotfix-1.5 文件夹,里面检出的是 release/1.5 分支。我打开这个文件夹,修完 bug,提交,推送,然后回到原来的工作目录继续开发 login 功能。整个过程没有任何切分支的操作,也不需要 stash,两边的工作完全不干扰。
用完之后我还发现了一个很实用的场景。有时候要验证一个问题是不是在老版本就存在,或者要复现一个用户报的 bug,需要切到几个月前的某个提交去看代码、跑测试。如果用传统方式切分支,当前目录的文件会被替换掉,编译产物可能要重新生成,IDE 的索引也要重新跑。
但用 worktree 就简单多了,直接创建一个临时的工作目录,检出那个老的提交:
git worktree add --detach ../temp-check 4f1e2c3 这个 --detach 参数的意思是不关联任何分支,直接检出某个提交,也就是所谓的"分离头指针"状态。我在这个临时目录里跑测试、看代码,验证完了直接删掉这个目录就行,原来的工作目录完全不受影响。
代码评审的时候也很方便。以前如果要本地验证别人的 PR,要么在当前分支上 pull 下来,要么切到一个临时分支。现在我会直接为这个 PR 创建一个 worktree,拉代码、跑测试、看效果,用完直接删掉。

当然,用了一段时间之后也发现了一些需要注意的地方。

最容易踩的坑是同一个分支不能同时在多个 worktree 里检出。如果你已经在一个 worktree 里检出了 main 分支,再去另一个 worktree 尝试检出 main,Git 会直接报错:branch 'main' already checked out。
这个限制其实挺合理的,因为 Git 需要保证同一个分支在同一时刻只有一个 HEAD 指针。如果你确实需要在多个地方同时看同一个提交的内容,可以用 --detach 参数,或者创建不同名字的分支指向同一个提交。
另外一个要注意的是清理工作。用完 worktree 之后,如果你直接把目录删了,Git 仓库里其实还保留着这个 worktree 的记录,在 .git/worktrees 目录下。这些记录不会自动清理,时间长了会积累一堆无效的条目。
正确的做法是用 git worktree remove 来删除:
git worktree remove ../hotfix-1.5 如果你已经手动删了目录,可以用 git worktree prune 来清理这些无效记录:
git worktree prune 我现在养成了一个习惯,在删除 worktree 之前先用 git worktree list 看一下当前有哪些 worktree,然后用 remove 正确删除。偶尔会跑一下 prune -n -v 看看有没有需要清理的残留记录。
还有个小技巧是关于目录组织的。一开始我创建 worktree 的时候比较随意,有的放在上级目录,有的放在 /tmp 下,后来发现这样管理起来很乱。现在我会在项目根目录旁边建一个 .wt 文件夹,所有的 worktree 都放在这里面:
git worktree add .wt/feature-x -b feature/x origin/main git worktree add .wt/hotfix-1.5 release/1.5 这样所有的 worktree 都集中在一个地方,清理的时候也方便。
说了这么多好处,但 worktree 也不是万能的。
如果你需要完全独立的 Git 配置,比如不同的 hooks、不同的全局设置,那还是得老老实实 clone 多个仓库。worktree 虽然有独立的工作目录,但底层的 .git 配置是共享的。
另外,如果你的项目用了 submodule,在 worktree 里处理起来会比较麻烦。Git 官方文档里也提到了,多 worktree 对 submodule 的支持还不够完善,建议谨慎使用。
还有就是团队协作的时候,如果其他人不熟悉 worktree,可能会对你的目录结构感到困惑。所以如果要在团队里推广,最好先统一一下使用规范,比如 worktree 的命名方式、存放位置等等。
用了这么久 worktree 之后,我觉得它最大的价值在于让并行工作变得简单了。以前需要在不同任务之间切换的时候,总是要考虑当前的改动怎么办、环境怎么保存、切回来会不会出问题。现在有了 worktree,每个任务就是一个独立的目录,互不干扰,想切就切,用完就删。
特别是对于那种需要频繁在多个分支之间切换的场景,比如同时维护多个版本、并行开发多个功能、临时验证历史问题,worktree 真的能省不少事。
回到开头说的 Cursor 2.0 的多 agent 模式,现在我也能理解为什么它要用 worktree 了。多个 agent 并行工作,每个 agent 需要独立的代码空间,但又要共享同一个仓库的历史和对象,worktree 确实是个很合适的选择。
如果你也经常遇到需要并行处理多个任务的情况,不妨试试 worktree。刚开始可能会觉得有点陌生,但用几次之后就会发现,这东西真的挺顺手的。