Git Worktree:一个仓库同时在多个分支工作,告别 stash 地狱

0 阅读4分钟

🚀 省流助手(速通结论)

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 修一下,赶紧。"

你的选项:

  1. stash → 切分支 → 修 hotfix → 切回来 → pop stash → 祈祷不冲突
  2. WIP commit → 同上 → 回头 reset
  3. 再 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 Bmain 分支)
│   ├── .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 窗口 Bmain 分支

两个窗口各管各的终端、GitLens、文件树。不需要任何特殊配置。


和软链接的区别

容易产生的误解:worktree 是不是类似 ln -s?

软链接 (symlink)git worktree
文件修改改一处,另一处同步可见各自独立,互不影响
inode同一个 inode各自真实的 inode
.git指向同一个worktree 的 .git 只存指针文本

软链接是让两个路径指向同一份数据,worktree 是共享对象库但各自持有独立的工作区 checkout。


和 submodule、monorepo 的关系

常有混淆,一句话区分:

  • worktree:同一个仓库,多个工作目录,共享 .git。解决"同时在多个分支工作"。
  • monorepo:一个仓库里放多个项目(packages/webpackages/api)。解决"多包协同发布"。
  • submodule:仓库嵌套仓库,各管各的 .git。解决"引用外部仓库的固定版本"。

它们不在一个维度——worktree 是操作手段,monorepo/submodule 是项目组织策略。你可以在 monorepo 里用 worktree,也可以在含 submodule 的仓库里用 worktree。


限制

  1. 同一分支不能被多个 worktree 同时 checkout——每个分支只能在一个 worktree 里活跃
  2. 子模块需要额外处理——每个 worktree 可能需要单独 git submodule update --init
  3. 不是 git clone --bare 的替代品——worktree 仍然需要完整的 .git 对象库

总结

下次有人跟你说"等我 stash 一下切个分支",你可以告诉他:

别 stash,用 git worktree add,三秒开一个平行宇宙。

你 clone 过一次的仓库,就是一座冰山。你平时看到的那个工作目录只是冰山一角——git worktree 让你把整座冰山都用起来。