我为什么不想再来回 `checkout` 分支了:用 `git worktree` 同时开发多个分支,干净很多
如果你平时只维护一个分支,git checkout 看起来没什么问题;但只要开始同时处理 dev、功能分支、临时修复分支,切分支这件事很快就会变得烦人。
最典型的几个问题几乎每个人都遇到过:
- 当前目录还有未提交改动,分支切不过去。
- 刚在
feature上改了一半,又被拉去修dev上的问题。 - 为了避免冲突先
stash一次,修完再stash pop,结果改动又缠到一起。 - 本地要同时跑两个分支,只能复制一份目录,最后哪个目录对应哪个分支自己都记不清。
我以前也是这么干的。直到项目开始同时并行多个需求后,我才真正体会到:很多混乱并不是 Git 太难,而是“一个目录承载多个分支”的工作方式本身就容易出错。
后来我把本地开发方式换成了 git worktree,最大的变化不是命令更高级,而是一个很朴素的原则终于成立了:一个目录只负责一个分支。
这篇文章就想把这件事讲清楚。
1. git worktree 到底解决了什么问题
git worktree 是 Git 自带功能,不需要单独安装。它允许同一个仓库在多个目录里同时检出不同分支。
核心理解只有一句话:
不是在一个目录里反复切分支,而是给不同分支各自分配一个目录。
这和“手工复制多个仓库目录”看起来有点像,但底层完全不是一回事。worktree 共享同一个 Git 仓库历史,不需要你真的复制一份完整仓库出来,所以它更适合长期并行开发。
当你开始把这个模型代入日常工作,会发现很多原来很别扭的动作都顺了:
-
dev可以长期常驻在一个目录里。 - 每个需求分支都能有自己的独立工作区。
- 不再需要频繁
stash、checkout、pop。 - 同时开两个编辑器窗口、两个终端、甚至两个本地服务都更自然。
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
这条命令会同时做两件事:
- 基于
dev创建feature/camera - 在新目录中直接检出这个新分支
这一点非常实用,因为它把“开新分支”和“准备开发目录”合并成了一次动作。
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. 一个很实用的最小工作流
如果你是个人开发或者小团队协作,我很建议直接用下面这个最小工作流:
- 保留一个长期存在的
devworktree。 - 每个需求从
dev再开一个 feature worktree。 - 每个目录只处理自己的分支,不在同一个目录里来回切。
- 需求完成后,合并回
dev。 - 删除已经完成的 feature worktree。
- 定期清理失效记录。
例如从 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. 和 merge、rebase 的关系是什么
worktree 解决的是“多个分支如何并行开发”的问题,不是“分支怎么合并”的问题。
也就是说,它不会替代 merge 或 rebase,但会让你在执行这些操作时更从容。
比如你想把 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_modulesdist- 构建缓存
- 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 去救场。对我来说,它最大的价值不是命令多高级,而是让本地开发环境终于变得更稳定、更可预测。
如果你现在还在一个目录里来回 checkout、stash、pop,而且手上经常同时挂着两个以上分支,那 git worktree 很值得尽早用起来。