🚀 省流助手(速通结论)
git worktree 让你基于同一份 Git 历史,同时拥有多个独立工作目录,每个目录 checkout 不同分支,互不打扰。
从此告别 stash / WIP commit / 重新 clone,切分支修 bug 就像打开新终端窗口一样自然。
磁盘上只存一份 .git 对象库,所有 worktree 共享历史,不浪费空间;每个 worktree 都是真实目录,VS Code 等工具零配置直接打开。
核心命令就一句:git worktree add <路径> <分支>,用完 remove 或手动删目录再 prune。
格局建议:不要再用 stash 管理上下文切换的痛苦,把每一个任务放在独立的 worktree 里,你的并行开发体验就是对传统工作流的降维打击。
开场:一个你肯定遇到过的场景
你在 feature/payment 分支写了 300 行代码,还没到能 commit 的程度。leader 突然说:"线上登录挂了,切 main 修一下,赶紧。"
你的选项:
- stash → 切分支 → 修 hotfix → 切回来 → pop stash → 祈祷不冲突
- WIP commit → 同上 → 回头 reset
- 再 clone 一份 → 费时费磁盘
有没有第 4 种?
有。git worktree。三秒搞定,worktree 间互不影响,不需要 stash,不需要 WIP commit。而且很多工作多年的开发者不知道这个命令。
一句话说清楚
git worktree 让你用同一个仓库的同一份 Git 数据库,创建多个独立的工作目录,每个目录可以 checkout 不同分支。
你只需要 clone 一次,之后加 worktree 就像开新终端窗口一样自然。
看一眼磁盘就懂了
假设你的项目在 ~/my-project,你在 feature 分支写了一半代码。现在要修 main 上的 bug:
# 在 ~/my-project 目录下执行
git worktree add ../my-project-hotfix main
磁盘结构变成了这样:
~/
├── my-project/ ← worktree A(feature 分支)
│ ├── .git ← 唯一的 Git 对象库(所有数据在这)
│ ├── src/ ← feature 分支的工作区
│ └── package.json
│
├── my-project-hotfix/ ← worktree B(main 分支)
│ ├── .git ← 不是目录,是指针文件!
│ ├── src/ ← main 分支的工作区
│ └── package.json
关键细节:my-project-hotfix/.git 不是一个目录,而是一个文本文件,内容差不多长这样:
gitdir: /home/you/my-project/.git/worktrees/my-project-hotfix
Git 内部会在 my-project/.git/worktrees/ 下存放每个 worktree 的 HEAD、index、stage 区。对象库始终只有一份,共享。
所以你磁盘上只有一个 .git 目录。不管加多少个 worktree,都不会重复存储 commit 历史。
实操
# 查看当前所有 worktree
git worktree list
# 基于 main 新建一个 hotfix worktree
git worktree add ../my-project-hotfix main
# 如果 main 已被当前 worktree checkout,用 -b 拉新分支
git worktree add -b hotfix-login ../my-project-hotfix main
# 用完了,删掉
git worktree remove ../my-project-hotfix
# 或直接 rm -rf + git worktree prune
默认第一个 clone 下来的目录本身就是主 worktree。之后加的都在 list 里看得到。
编辑器怎么办?没有任何障碍
每个 worktree 在文件系统上是真实独立的目录。对 VS Code 来说它就是普通文件夹。
~/my-project → 开 VS Code 窗口 A,feature 分支
~/my-project-hotfix → 开 VS Code 窗口 B,main 分支
两个窗口各管各的终端、GitLens、文件树。不需要任何特殊配置。
和软链接的区别
容易产生的误解:worktree 是不是类似 ln -s?
| 软链接 (symlink) | git worktree | |
|---|---|---|
| 文件修改 | 改一处,另一处同步可见 | 各自独立,互不影响 |
| inode | 同一个 inode | 各自真实的 inode |
| .git | 指向同一个 | worktree 的 .git 只存指针文本 |
软链接是让两个路径指向同一份数据,worktree 是共享对象库但各自持有独立的工作区 checkout。
和 submodule、monorepo 的关系
常有混淆,一句话区分:
- worktree:同一个仓库,多个工作目录,共享
.git。解决"同时在多个分支工作"。 - monorepo:一个仓库里放多个项目(
packages/web、packages/api)。解决"多包协同发布"。 - submodule:仓库嵌套仓库,各管各的
.git。解决"引用外部仓库的固定版本"。
它们不在一个维度——worktree 是操作手段,monorepo/submodule 是项目组织策略。你可以在 monorepo 里用 worktree,也可以在含 submodule 的仓库里用 worktree。
限制
- 同一分支不能被多个 worktree 同时 checkout——每个分支只能在一个 worktree 里活跃
- 子模块需要额外处理——每个 worktree 可能需要单独
git submodule update --init - 不是
git clone --bare的替代品——worktree 仍然需要完整的.git对象库
总结
下次有人跟你说"等我 stash 一下切个分支",你可以告诉他:
别 stash,用
git worktree add,三秒开一个平行宇宙。
你 clone 过一次的仓库,就是一座冰山。你平时看到的那个工作目录只是冰山一角——git worktree 让你把整座冰山都用起来。