git worktree 用来管理本地同一个仓库(repository)下的多个工作区(working tree)。它允许你在不同目录中同时检出多个分支或提交,从而并行开发/测试。
它解决的核心痛点是:
main 修 bug、feature/* 开发新需求、release/* 打包)git checkout一句话:git worktree 让”一个仓库,多份工作区”成为原生能力。
Git 的一个”仓库”(repository)可以绑定多个工作区:
git clone 得到的目录)git worktree add 创建)这些工作区共享同一套对象数据库(.git/objects),因此:
典型结构(示意):
repo/ # 主 worktree
├── .git/ # 主 worktree 的 git 目录(或 gitfile)
├── src/
└── ...
repo/.git/worktrees/ # worktree 元数据(每个附加 worktree 一份)
../repo-feature-x/ # 附加 worktree 1
├── .git # 指向主仓库的 gitfile
├── src/
└── ...
../repo-hotfix/ # 附加 worktree 2
├── .git # 指向主仓库的 gitfile
├── src/
└── ...
工作原理示意图:
┌─────────────────────────────────────────────────────┐
│ 共享的 Git 对象数据库 │
│ repo/.git/objects, refs, hooks │
└─────────────────────────────────────────────────────┘
▲
│ 共享引用
┌───────────────┼────────────────┐
│ │ │
┌───▼──┐ ┌─────▼───┐ ┌─────▼──┐
│ repo │ │repo-fe │ │repo-fix│
│(main)│ │-x │ │ │
└──────┘ │(feature)│ │(hotfix)│
└─────────┘ └────────┘
注意:附加 worktree 目录中通常不会有完整的
.git/目录,而是一个指向主仓库的”gitfile”。
很多人第一次遇到并行开发需求时,会用 git stash 或者多次 git clone。它们都能”凑合”,但 git worktree 更适合长期和频繁并行。
| 方案 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
git stash |
临时切走一会儿 | 快;不新增目录 | 容易忘;冲突概率高;不适合多线程工作 |
多次 git clone |
彻底隔离 | 最直观;彼此无关联 | 占空间;更新维护成本高;多个 clone 的 remotes/配置容易不一致 |
git worktree |
并行分支长期共存 | 省空间;共享对象;切换成本低;结构清晰 | 需要理解 worktree 约束;需要正确清理 |
Git 默认不允许同一个本地分支同时被多个 worktree 检出:
worktree add 一个已被检出的分支,会报错# 假设 main 已在主 worktree 检出
git worktree add ../repo-main2 main
# fatal: 'main' is already checked out at '/path/to/repo'
如果你确实需要同一份代码在两个目录存在,通常有三种方法:
你可以把 worktree 绑定到某个提交(而不是分支),这样的 worktree 称为 detached HEAD 状态:
git worktree add --detach ../repo-debug HEAD~3
核心特性:
重要:在 detached worktree 里做了改动就立刻创建分支
git switch -c <branch>保存。
git worktree 从 Git 2.5 引入,现代 Git 基本都内置。
git --version
# 建议 >= 2.30(体验更好)
说明:不同平台自带 Git 版本差异较大(特别是 macOS 的系统 Git)。如果遇到行为不一致,优先升级 Git(例如 brew 安装)。
git worktree list
输出示例:
/Users/me/repo abc1234 [main]
/Users/me/repo-feature-x def5678 [feature/x]
/Users/me/repo-hotfix 9876fed [hotfix/urgent]
常用选项:
# 输出机器可读格式(便于脚本解析)
git worktree list --porcelain
当你只提供路径时:
git worktree add ../hotfix
Git 会把路径的最后一段(这里是 hotfix)当做分支名:
hotfix 分支不存在:自动从当前 HEAD 创建并检出 hotfixhotfix 分支已存在:尝试直接检出(但如果它已被其它 worktree 占用会失败,除非 --force)# 把已存在的分支检出到新 worktree
git worktree add ../repo-feature-x feature/x
# -b: 创建新分支 | ../repo-feature-x: worktree 目录 | origin/main: 新分支起点
git worktree add -b feature/x ../repo-feature-x origin/main
含义:
-b feature/x:创建本地分支../repo-feature-x:worktree 目录origin/main:以哪个起点创建(也可以是 main 或某个 commit)# 基于某个版本号或提交 hash 创建 detached worktree
git worktree add --detach ../repo-debug v1.2.3
进入某个 worktree 后,它和普通仓库使用方式一致:
cd ../repo-feature-x
git status
# 在该 worktree 内切换到新分支
git switch -c feature/x-2
注意:如果你在附加 worktree 里
git switch main,可能会失败(因为 main 已在主 worktree 检出)。
git worktree remove ../repo-feature-x
只有”干净”的 worktree(无已跟踪文件修改、无未跟踪文件)才能被删除;否则 Git 会拒绝:
# 强制删除(谨慎)
git worktree remove --force ../repo-feature-x
当你需要重命名目录或调整 worktree 的存放位置时,优先用 move 而不是手动 mv:
# 把 worktree 移动到新路径
git worktree move ../repo-feature-x ../repo-feature-x-renamed
注意:主 worktree 不能用
move。如果你手动移动了主 worktree,建议用git worktree repair重新建立关联。
当 worktree 放在可移动磁盘/网络盘上(可能会临时断开挂载)时,建议锁定它以避免被自动清理:
# 锁定,附带原因说明
git worktree lock --reason "mounted on external disk" ../repo-debug
# 解锁
git worktree unlock ../repo-debug
当你手动移动了 worktree 目录,或 .git 连接文件损坏导致 worktree 失联时,可以尝试修复:
# 在任意 worktree 里执行,修复当前 worktree
git worktree repair
# 修复指定路径(可一次多个)
git worktree repair ../repo-feature-x ../repo-hotfix
当你手动删除了 worktree 目录,或者目录损坏时,仓库内可能残留记录。
git worktree prune
建议搭配检查:
git worktree list
目标:
../repo-feature-x 开发 featurerepo/ 保持 main 干净,随时修 hotfix操作流程:
# 1. 主目录:保持 main
cd repo
git switch main
# 2. 创建 feature worktree(新分支)
git worktree add -b feature/x ../repo-feature-x origin/main
# 3. 在 feature worktree 开发
cd ../repo-feature-x
# 编写代码、测试、提交...
git add .
git commit -m "feat: 添加新功能"
# 4. 紧急 bug 来了:回到主目录处理
cd ../repo
git switch -c hotfix/urgent
# 修复 bug、测试、提交、push...
git add .
git commit -m "fix: 修复紧急 bug"
git push
优势:
例子:
main 跑全量测试feature/x 跑增量/本地开发# worktree A: 主目录跑测试
cd repo
npm test
# worktree B: 另开窗口,在 feature worktree 开发和调试
cd ../repo-feature-x
npm run dev
提示:如果项目会生成大量构建产物(dist、.next、target 等),worktree 比 “同目录切分支” 更干净。
你可以把某个远端分支拉到独立 worktree,用完就删:
# 1. 拉取 PR 分支
git fetch origin pull/123/head:pr/123
# 2. 创建 worktree 检出该分支
git worktree add ../repo-pr-123 pr/123
# 3. 在隔离环境复现、跑测试、review
cd ../repo-pr-123
npm test
npm run build
# 4. 用完后清理(两个命令都需要)
cd ../repo
git worktree remove ../repo-pr-123
git branch -D pr/123
detached worktree 特别适合调试历史版本。根据需求不同,有两类操作流程:
目标:快速在某个历史版本验证 bug 是否存在,验证后丢弃。
# 1. 创建 detached worktree 检出历史版本
git worktree add --detach ../repo-verify v1.0.0
# 2. 进入 worktree 并验证
cd ../repo-verify
npm install
npm test # 验证 bug 是否存在
# 3. 验证完毕,返回主目录清理 worktree(改动自动丢弃)
cd ../repo
git worktree remove ../repo-verify
优点:
目标:在历史版本上修复 bug,并保存为新分支。
# 1. 创建 detached worktree 检出历史版本
git worktree add --detach ../repo-bugfix v0.9.0
# 2. 进入 worktree 并修复问题
cd ../repo-bugfix
# 编写、测试修复代码...
npm test
# 3. 重要:改动需要保存,立刻创建分支
git switch -c fix/v0.9.0-patch
# 此时所有修改都已转移到新分支
# 可以继续 git add / git commit(如果有新改动)
# 4. 返回主仓库,清理 worktree(分支已安全保存)
cd ../repo
git worktree remove ../repo-bugfix
# 5. 新分支已创建并包含改动,可继续操作
git log -1 --oneline fix/v0.9.0-patch
git switch fix/v0.9.0-patch # 继续在该分支上工作
核心原则:改动完成立即创建分支,否则删除 worktree 时丢失。
当你需要对比 rebase 前后行为,worktree 特别好用:
# 1. 创建一个对照 worktree(记录 rebase 前状态)
git worktree add ../repo-before-rebase main
# 2. 在主目录做 rebase
cd repo
git switch feature/x
git rebase main
# 3. 在对照 worktree 跑验证(old 行为)
cd ../repo-before-rebase
npm test
# 4. 回到主目录跑验证(new 行为)
cd ../repo
npm test
# 5. 对比结果,确认 rebase 安全后清理
git worktree remove ../repo-before-rebase
遇到问题时可以用以下命令快速诊断:
# 查看分支被哪个 worktree 占用
git worktree list
# 查看某个 worktree 的 gitfile 指向
cat <worktree-path>/.git
# 检查 worktree 列表是否有残留
git worktree list
# 清理失效元数据
git worktree prune
推荐策略:
~/code/repo~/code/wt/repo-<branch> 或 ../repo-<branch>这样好处是:
repo-wt-main
repo-wt-feature-x
repo-wt-hotfix-urgent
repo-wt-pr-123
文件夹名能直接体现用途,比只用分支名更直观。
某些构建脚本会写入固定路径(比如 dist/),这在 worktree 模式下一般没事,
但如果你把输出目录重定向到共享路径(例如 ../dist),可能造成互相覆盖。
worktree 删除只影响工作区,不一定会删除分支。
常见流程:
# 1. 先 remove worktree
git worktree remove ../repo-feature-x
# 2. 再决定是否删分支
git branch -d feature/x
# 或强制删除
git branch -D feature/x
# 先清理元数据
git worktree prune
# 再确认
git worktree list
worktree 对子模块也能用,但注意:
建议:
git submodule update --init --recursive| 维度 | Worktree | Stash |
|---|---|---|
| 并行开发 | ✅ 天然支持 | ❌ 需要不停存取 |
| 上下文保存 | ✅ 目录即上下文 | ⚠️ 容易忘记 stash 内容 |
| 适合时长 | 中长期 | 短期 |
| 冲突风险 | 低(彼此隔离) | 中高(恢复时易冲突) |
| 维度 | Worktree | 多次 clone |
|---|---|---|
| 磁盘占用 | 低(共享 objects) | 高(重复 objects) |
| 远端/配置一致性 | ✅ 天然一致 | ❌ 可能不一致 |
| 隔离程度 | 中(共享仓库) | 高(完全独立) |
| 适用场景 | 并行分支开发 | 需要彻底隔离配置或权限时 |
Q1:为什么我不能在第二个 worktree 里 checkout main?
因为 main 已被另一个 worktree 检出,Git 会阻止同一分支被多个 worktree 同时使用。
解决思路:
git switch -c main-copygit worktree add --detach <path> mainQ2:我把 worktree 目录 rm -rf 了,现在 git worktree list 还在?
运行:
git worktree prune
这会清理所有失效的 worktree 元数据。
Q3:删除 worktree 时报错”worktree contains modified files”怎么办?
这是安全保护——Git 不允许删除包含未提交改动的 worktree。解决方案:
# 方案 1: 进入 worktree 提交或放弃改动
cd ../repo-feature-x
git add .
git commit -m "save changes"
# 或丢弃改动
git reset --hard HEAD
# 方案 2: 强制删除(不推荐,容易丢失代码)
git worktree remove --force ../repo-feature-x
Q4:worktree 中的改动会影响其他 worktree 吗?
不会。每个 worktree 有独立的工作目录、index 和 HEAD,改动不会相互影响。但是:
Q5:worktree 对大仓库有特殊支持吗?
有。worktree 特别适合大仓库:
.git/objects,不重复存储git worktree 是解决并行分支开发的”正统方案”,尤其适合:
核心要点速记:
git worktree remove,异常时 git worktree prune| 目的 | 命令 | 说明 |
|---|---|---|
| 查看 worktree | git worktree list |
列出所有 worktree |
| 新建 worktree(已有分支) | git worktree add <path> <branch> |
把分支检出到新目录 |
| 新建 worktree(新分支) | git worktree add -b <b> <path> <start> |
最常用 |
| detached worktree | git worktree add --detach <path> <rev> |
debug/回归 |
| 删除 worktree | git worktree remove <path> |
删除工作区 |
| 清理记录 | git worktree prune |
清掉失效 worktree 元数据 |