Git worktree:多工作区并行开发与实践
git worktree 允许在同一 Git 仓库 (同一套 .git 对象库与 refs)下挂载多个工作目录 ;每个工作目录可检出不同分支 ,并行开发而无需频繁 stash / checkout。本文归纳概念、常用命令、与 git clone 多次 的差异、踩坑点与目录约定,并附 Mermaid 关系图与 Monorepo 协作向工作流示例。命令与行为以所用 Git 版本 为准,建议 ≥ 2.5(worktree 成熟后)。
目录
- 一句话理解
- 解决什么问题
- 核心概念
- 仓库与工作区关系(示意)
- 常用命令
- [与多次 clone 的对比](#与多次 clone 的对比)
- 目录上「两套代码、一份仓库」
- 进阶要点
- 踩坑与修复
- 实践建议
- [前端 / 后端 / Monorepo 工作流示例](#前端 / 后端 / Monorepo 工作流示例)
- worktree、分支与提交(关系图)
- 免责声明
一句话理解
| 说法 | 含义 |
|---|---|
| worktree | 一个 .git 仓库 ,多个工作目录 ;各目录可绑定不同分支 ,共用提交历史、对象库、分支与 tag |
| 对比 clone 两份 | 两次 clone = 两个独立仓库 (两套 .git);worktree = 一个仓库,多个「代码窗口」 |
解决什么问题
单工作区时常遇到的矛盾:
| 场景 | 痛点 |
|---|---|
main 修 bug,同时 feature/xxx 开发 |
反复 checkout,编译缓存、本地改动易乱 |
| 临时切分支看代码 / 跑测试 | 需要 stash 或临时 commit |
| 并行跑不同分支的构建 | 同一目录难以同时进行 |
worktree 让这些工作落在不同目录 ,各自绑定分支,共享同一仓库数据。
核心概念
- 一个 repo :根目录下的
.git(或 bare 仓库)保存对象与 refs。 - 多个 worktree :每个 worktree 是一个独立工作目录 ,检出某一条分支(或 detached HEAD)。
- 共享 :commits、objects、
refs/heads等只有一份 ;未提交的 working tree 内容 在各目录间隔离。
硬规则 :同一条分支不能同时被两个 worktree 检出 (否则会报 already checked out at ...)。
仓库与工作区关系(示意)
单一 Git 仓库(.git)
对象库 objects
refs / HEAD
工作目录 A
例如绑定 main
工作目录 B
例如绑定 feature/login
工作目录 C
例如 release 或 detached
常用命令
| 操作 | 命令示例 | 说明 |
|---|---|---|
| 新增 worktree | git worktree add ../project-feature feature/login |
在 ../project-feature 建目录并检出 feature/login(分支可不存在时配合 -b 新建) |
| 列出 worktree | git worktree list |
显示路径与当前检出分支 |
| 删除 worktree | git worktree remove ../project-feature |
推荐 ;不删除远程分支,只移除工作区登记 |
| 新建分支并添加 | git worktree add ../foo -b feature/foo |
一步创建分支与工作目录 |
| 清理残留登记 | git worktree prune |
在误删目录后清理 .git/worktrees 中的陈旧记录 |
在任意 worktree 里 git fetch:所有 worktree 可见新分支与更新(共用 refs)。
与多次 clone 的对比
| 对比项 | git clone 两份 |
git worktree |
|---|---|---|
.git 份数 |
两套 | 一套 |
| 磁盘占用 | 对象库大致翻倍 | 新增目录主要多一份工作树文件 ,对象共享 |
| 分支 / 提交 | 彼此独立,需分别 fetch/pull | 实时共享同一套历史与分支 |
| 同一分支开两份 | 可以(实为两个仓库各检同一分支名) | 不可以(同一仓库内一条分支只能被一个 worktree 占用) |
| 典型用途 | 不同人、不同机器、强隔离 | 同人同项目并行多分支 |
选型口诀 :给别人用 / 要完全隔离 / 同一分支要两个实例 → clone ;自己并行多分支 → worktree。
目录上「两套代码、一份仓库」
主仓库示例:
text
project/
├── .git/ ← 真正的仓库
├── src/
└── package.json
执行:
bash
git worktree add ../project-feature feature/login
常见结果:
text
project/ ← worktree 1
├── .git/
├── src/
└── package.json
project-feature/ ← worktree 2(额外工作目录)
├── .git ← 通常是「文件」,不是目录
├── src/
└── package.json
附加 worktree 里的 .git 多为文件 ,内容指向主仓库下的 worktrees/...,例如:
text
gitdir: /path/to/project/.git/worktrees/project-feature
因此:删目录不等于正确移除 worktree ,应使用 git worktree remove,否则需 git worktree prune 收拾残留。
进阶要点
| 问题 | 结论 |
|---|---|
附加 worktree 里的 .git 是什么? |
多为文件 ,gitdir: 指向主仓库的 worktrees/<name> |
能在子 worktree 里再 git worktree add 吗? |
应在主仓库(或登记为 main worktree 的那棵)执行 ;在错误目录执行易失败或易乱,习惯上回到原项目根管理 worktree |
| 能否检出新分支? | 可以:add 后 checkout -b,或 git worktree add path -b new-branch |
| 在 worktree A 的提交,B 能看到吗? | 能 (同一 refs);未提交改动仍只在各自目录 |
踩坑与修复
| 坑 | 说明 | 处理 |
|---|---|---|
rm -rf 删掉 worktree 目录 |
.git/worktrees 可能仍残留 |
git worktree prune 或补做 remove(若路径还在) |
| 同一分支绑定两次 | 报错 already checked out |
换分支,或对第二棵树用 detached :git worktree add ../hotfix HEAD(按需再建分支) |
IDE 不认 .git 文件 |
老插件可能只认 .git 目录 |
重开文件夹、指定仓库根,或升级工具 |
在 worktree 里再 git init |
破坏与主仓库的关联 | 不要这样做 |
实践建议
- 目录约定 :例如
my-repo/main、my-repo/feature-xxx、my-repo/hotfix-yyy,主目录长期固定 main/develop,减少在主 worktree 上乱切分支。 - 用完即删 :
git worktree list→git worktree remove <path>,避免僵尸登记。 - 配合
git fetch:任一棵 worktree fetch 即可,全局可见。 - 团队新人 :若团队不熟悉 worktree,可仍以 clone 为主;worktree 更适合已熟悉 Git的同库并行。
前端 / 后端 / Monorepo 工作流示例
以下适用于 Monorepo (如 apps/web、apps/api、packages/shared),用 worktree 按分支拆目录 ,各自装依赖、跑脚本,合并仍在同一远程仓库完成。
| 步骤 | 操作思路 |
|---|---|
| 1 | 在主仓库路径 保留 main(或 develop)worktree,作集成与发版基线 |
| 2 | git worktree add ../myrepo-fe -b feature/web-redesign:前端大改独立目录 |
| 3 | git worktree add ../myrepo-be -b feature/api-v2:后端并行开发 |
| 4 | 各目录内分别 npm install / pnpm install(或各语言等价),构建缓存互不覆盖 |
| 5 | 约定 PR 合并目标分支 ;合并后 git worktree remove 废弃目录,需要时再 add 新分支 |
说明 :若仓库不是 Monorepo,也可同样用「一目录一分支」;与「前后端分仓库」的 clone 策略不同,worktree 前提是同一本地仓库。
worktree、分支与提交(关系图)
共享:objects + refs
检出
检出
commit ...
commit ...
branch: main
branch: feature/x
Worktree 目录 1
Worktree 目录 2
语义要点:提交 DAG 与分支指针只有一份 ;多个 worktree 只是不同目录 指向不同 ref(或 detached 某 commit)。
免责声明
本文用于 Git 学习与团队规范参考;具体报错信息与选项以 git help worktree 及当前 Git 版本为准。
主题:Git worktree、多分支并行、与 clone 对比、Monorepo 工作流。