阅读视图

发现新文章,点击刷新页面。

我为什么不想再来回 `checkout` 分支了:用 `git worktree` 同时开发多个分支,干净很多

如果你平时只维护一个分支,git checkout 看起来没什么问题;但只要开始同时处理 dev、功能分支、临时修复分支,切分支这件事很快就会变得烦人。

最典型的几个问题几乎每个人都遇到过:

  • 当前目录还有未提交改动,分支切不过去。
  • 刚在 feature 上改了一半,又被拉去修 dev 上的问题。
  • 为了避免冲突先 stash 一次,修完再 stash pop,结果改动又缠到一起。
  • 本地要同时跑两个分支,只能复制一份目录,最后哪个目录对应哪个分支自己都记不清。

我以前也是这么干的。直到项目开始同时并行多个需求后,我才真正体会到:很多混乱并不是 Git 太难,而是“一个目录承载多个分支”的工作方式本身就容易出错。

后来我把本地开发方式换成了 git worktree,最大的变化不是命令更高级,而是一个很朴素的原则终于成立了:一个目录只负责一个分支。

这篇文章就想把这件事讲清楚。

1. git worktree 到底解决了什么问题

git worktree 是 Git 自带功能,不需要单独安装。它允许同一个仓库在多个目录里同时检出不同分支。

核心理解只有一句话:

不是在一个目录里反复切分支,而是给不同分支各自分配一个目录。

这和“手工复制多个仓库目录”看起来有点像,但底层完全不是一回事。worktree 共享同一个 Git 仓库历史,不需要你真的复制一份完整仓库出来,所以它更适合长期并行开发。

当你开始把这个模型代入日常工作,会发现很多原来很别扭的动作都顺了:

  • dev 可以长期常驻在一个目录里。
  • 每个需求分支都能有自己的独立工作区。
  • 不再需要频繁 stashcheckoutpop
  • 同时开两个编辑器窗口、两个终端、甚至两个本地服务都更自然。

2. 我最常见的实际场景

拿一个真实的本地目录举例:

D:\www\smart-park-app-patrol-car

这时候如果我执行:

git worktree list

可能会看到类似结果:

D:/www/smart-park-app-patrol-car      67c10b6 [feature/voice-intercom]
D:/www/smart-park-app-patrol-car-dev  6b89ca7 [dev]

这个结果表达的信息其实很明确:

  • D:\www\smart-park-app-patrol-car 对应 feature/voice-intercom
  • D:\www\smart-park-app-patrol-car-dev 对应 dev

从这里开始,开发习惯就会发生变化。

以前的思路是:进入同一个目录,然后不停切分支。
现在的思路是:要改哪个分支,就直接进入那个分支对应的目录。

这看起来只是路径变化,但它带来的好处非常直接:分支边界终于变成了物理边界。

3. 最值得先记住的几个命令

3.1 查看当前有哪些 worktree

git worktree list

这是最常用的命令之一。它能让你快速确认当前仓库已经有哪些工作目录、每个目录对应哪个分支。

如果你本地并行维护多个需求,这个命令基本等于“先看地图再行动”。

3.2 基于已有分支创建一个新目录

比如我已经有 dev 分支,想单独给它一个目录:

git worktree add ..\smart-park-app-patrol-car-dev dev

这条命令的意思是:

  • 在当前仓库的同级目录创建 smart-park-app-patrol-car-dev
  • 这个目录直接检出 dev 分支

从此以后,dev 就可以固定在这个目录里长期存在。

3.3 创建新分支并同时建立 worktree

如果我想从 dev 拉一个新需求分支:

git worktree add ..\smart-park-app-patrol-car-feature-camera -b feature/camera dev

这条命令会同时做两件事:

  1. 基于 dev 创建 feature/camera
  2. 在新目录中直接检出这个新分支

这一点非常实用,因为它把“开新分支”和“准备开发目录”合并成了一次动作。

3.4 不切目录直接看另一个 worktree 状态

有时候你并不想切到那个目录,只想看一下状态:

git -C D:\www\smart-park-app-patrol-car-dev status

这个用法在 Windows PowerShell 下很顺手,适合快速确认另一个工作区有没有未提交改动。

3.5 删除不用的 worktree

git worktree remove ..\smart-park-app-patrol-car-feature-camera

这个动作会删除对应工作目录,并解除它和主仓库的关联。

但这里一定要注意,删除前先确认目录里没有未提交改动,否则很容易把自己还没处理的变更一起带走。

4. 为什么它比反复 checkout 更适合日常开发

很多人第一次接触 worktree 时,容易把它理解成“高级一点的分支切换工具”。但我实际用下来,觉得它更像是一种工作方式的切换。

直接 checkout 的问题,不在于命令本身,而在于它要求一个目录在不同时间承担多个分支的职责。

这会带来几个常见副作用:

  • 一个目录里的未提交改动会阻塞另一个分支的切换。
  • 你很难一眼看出当前终端到底在哪个分支上。
  • 两个分支共用一个工作目录时,构建缓存、依赖状态和本地临时文件容易互相污染。
  • 当你一边开发需求、一边处理线上修复时,思路很容易被切碎。

worktree 的优势,恰恰是把这些问题转移掉了。

因为一个目录固定一个分支,所以:

  • 当前目录改动只属于当前分支。
  • 本地服务、构建产物和依赖状态天然分开。
  • 哪个窗口对应哪个分支,一眼就知道。
  • 你不需要再通过 stash 给自己制造额外状态。

5. 一个很实用的最小工作流

如果你是个人开发或者小团队协作,我很建议直接用下面这个最小工作流:

  1. 保留一个长期存在的 dev worktree。
  2. 每个需求从 dev 再开一个 feature worktree。
  3. 每个目录只处理自己的分支,不在同一个目录里来回切。
  4. 需求完成后,合并回 dev
  5. 删除已经完成的 feature worktree。
  6. 定期清理失效记录。

例如从 dev 再开一个需求:

cd D:\www\smart-park-app-patrol-car-dev
git pull
git worktree add ..\smart-park-app-patrol-car-feature-camera -b feature/camera dev

这个流程的好处是,dev 永远保留在一个稳定目录里,而不是每次都被你切来切去。

6. 和 mergerebase 的关系是什么

worktree 解决的是“多个分支如何并行开发”的问题,不是“分支怎么合并”的问题。

也就是说,它不会替代 mergerebase,但会让你在执行这些操作时更从容。

比如你想把 dev 的最新代码同步到功能分支,可以先更新 dev

cd D:\www\smart-park-app-patrol-car-dev
git pull

再去功能分支目录执行:

cd D:\www\smart-park-app-patrol-car-feature-camera
git merge dev

或者:

git rebase dev

这一步和传统 Git 工作流并不冲突,只是因为目录分开了,整个过程会更清晰。

7. 本地目录怎么命名最不容易乱

我建议一开始就定一个统一命名规则。比如:

D:\www\
  smart-park-app-patrol-car
  smart-park-app-patrol-car-dev
  smart-park-app-patrol-car-feature-camera
  smart-park-app-patrol-car-feature-voice

这个规则最大的好处不是“好看”,而是低认知成本。

看到目录名,你就能立刻知道:

  • 这是哪个项目
  • 这是 dev 还是某个 feature
  • 这个终端该提交到哪里

对并行开发来说,这种明确性很重要。

8. 它会不会更占空间

会,但通常没有很多人想象中那么夸张。

git worktree 会给每个分支准备一份自己的工作目录文件,但 Git 历史对象本身是共享的,所以它通常比“完整复制多个仓库目录”更省。

真正更占空间的,往往不是 Git,而是这些东西:

  • node_modules
  • dist
  • 构建缓存
  • IDE 生成文件

所以如果你做的是前端、移动端或者多模块项目,空间成本主要还是来自依赖和产物,而不是 worktree 本身。

9. 我遇到最多的几个报错

9.1 某个分支已经被别的 worktree 占用

如果 Git 提示某个分支已经被检出,通常说明这个分支已经在另一个 worktree 目录里存在了。

先执行:

git worktree list

找到对应目录后,要么直接继续使用那个目录,要么先删除旧 worktree,再重新创建。

9.2 删除 worktree 失败

最常见原因有两个:

  • 目录里还有未提交改动
  • 目录正被终端、编辑器或者运行中的进程占用

这种时候不要急着强删,先检查:

git status

确认没有遗留改动后,再关闭相关终端和程序,再执行 git worktree remove

9.3 目录被手工删掉了,但记录还在

这时候不用慌,执行:

git worktree prune

它会清理已经失效的 worktree 记录。

10. 最后一句结论

我现在对 git worktree 的理解很简单:它不是帮你“更快地切分支”,而是帮你尽量少切分支。

一旦项目进入并行开发阶段,这种变化会非常明显。你不再需要让一个目录承担所有分支的上下文,也不需要频繁用 stash 去救场。对我来说,它最大的价值不是命令多高级,而是让本地开发环境终于变得更稳定、更可预测。

如果你现在还在一个目录里来回 checkoutstashpop,而且手上经常同时挂着两个以上分支,那 git worktree 很值得尽早用起来。

参考资料

❌