Git 同时开发多个分支,这个事听起来像是高端操作,其实本质就是一个非常现实的问题:你手上同时压着几个需求或者几件事,A 分支改到一半,临时要切去 B 分支修个紧急 bug,结果一 git switch 就被各种报错糊脸——要么是未提交的改动冲突,要么是构建产物互相污染,要么是本地服务端口被占。硬切几次之后,你就会明白"同时开发多个分支"不是炫技,是救命。
这篇内容我基于自己平时实际操作的方案来写,核心是三个东西:git worktree、git stash 的合理搭档、以及一套能"同时推进多条线"的工作流设计。适合那些已经熟悉 git add、commit、push 这类基本操作,但还没找到多分支并行开发正确姿势的同学。不扯理论,全部是能直接抄走的命令和思路。
1. "同时开发多个分支"到底在解决什么问题
1.1 切换分支的代价,比你以为的大得多
大多数人第一次遇到"多分支并行"的需求,第一反应是:那我切分支不就行了?确实,在改动非常少、提交非常干净的情况下,git switch 是够用的。但一旦你手里同时进行的是两三个功能,每个功能都动了几十上百个文件,问题就来了。
先说最直接的操作冲突。Git 允许你带着未提交的改动切换分支的前提是:这些改动不和新分支的目标状态产生冲突。什么意思?就是你改了文件 A,切过去的那个分支也改了文件 A,Git 就会拒绝切换,让你先 commit 或者 stash。这个机制本身没错,但问题是——你手里改到一半的代码可能是个中间状态,根本不能提交。你舍不得提交,又必须马上切去修线上 bug,最经典的做法就是 git stash,切过去,修完,再切回来 pop。
每一个流程走下来需要多少时间成本?stash 一下、记录一下 stash 的名字、切分支、切回来、pop、处理可能的冲突。这些操作每一步都有心智负担,而且分支一多,你完全会忘记某个 stash 里面放的是什么。我见过有人 stash 列表里堆了十几个条目,最后直接放弃,全部删掉重写。
1.2 比操作冲突更隐蔽的,是构建产物的污染
真正让我下定决心改用 worktree 的,其实不是切换冲突,而是构建缓存和服务进程的互相干扰。你写前端项目的时候,node_modules 是共享的,开发服务器也好、构建缓存也好,都会以当前目录下的文件状态为基准。你在 A 分支跑着 dev server,然后切去 B 分支,按下回车的那一瞬间,dev server 看到的可能就是一堆混合的文件结构。
这种场景下你遇到的最典型问题是:A 分支引入的新依赖,在 B 分支里根本不存在,但 node_modules 里还残留着,能跑;或者反过来,A 分支删掉了个依赖,切到 B 分支发现编译报错,一查是这个依赖被 A 分支的动作污染了。遇到这种问题,你往往要花比写代码更长的时间去反复 rm -rf node_modules && npm install,原因根本不是代码逻辑,而是你的"工作空间"本身不干净。
1.3 物理隔离 vs 逻辑隔离:你需要的是复制一份工作目录
很多人误以为 Git 自带的分支切换就是一种隔离,其实它只是"逻辑隔离"——同一份工作目录,同一份文件系统,Git 在切换时把文件替换成对应分支的内容。逻辑隔离解决的是"代码内容"的问题,解决不了"运行态进程"和"目录上下文"的问题。
所以,如果你的并行开发涉及前端编译、本地服务、数据库迁移、依赖安装这些重操作,你真正需要的是一个"物理隔离"方案:每个分支各自拥有一份完整的工作目录,各个目录里的构建产物、依赖缓存、进程互不干扰。这听起来像是要克隆好几份仓库,其实 Git 早就给出了官方方案,那就是 git worktree。
我们看一张简单的对比,感受一下两种思路的区别:
| 场景 | 仅用 git switch |
git worktree 多工作树 |
|---|---|---|
| 未提交改动较多时切换 | 被拦截,需要 stash/commit | 不需要,另一个分支有自己的目录 |
| dev server / 热重载 | 切换后必须重启,可能缓存污染 | 各目录独立,无需重启干扰 |
| 分支间依赖差异 | node_modules 共享,易出幻觉 |
各自目录独立,互不影响 |
| 同时查看两分支代码 | 靠编辑器切换文件,易乱 | 两个窗口直接打开两个路径 |
| 本地服务端口 | 只能错开端口,操作繁琐 | 天然独立,端口可相同 |
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. git worktree:真正意义上的多分支并行引擎
2.1 worktree 的原理,一句话说清楚
git worktree 的作用是,把一个仓库的多个分支分别关联到不同的物理目录。每个目录都是独立的工作区,但共享同一个 .git 对象库。也就是说,你在 A 目录里 commit,B 目录里立刻能看到,因为底层是同一个仓库。你不需要 clone 多份,不需要各自配置远程,也不需要担心代码分叉到完全不同的仓库里去。
它怎么实现的?Git 在 .git/worktrees/ 下面为每个额外的 worktree 创建了一个注册记录,记录里包含这个工作树指向哪个分支、HEAD 是什么、对应的 .git 文件链接在哪里。
