Git Worktree 使用案例说明
一、什么是 Worktree?
Git 默认情况下,一个仓库只有一个工作目录(Working Directory)。git worktree 允许你为同一个仓库关联多个工作目录,每个目录可以独立检出不同的分支,同时共享底层的 .git/objects 对象库,不会重复占用磁盘空间。
Git 将工作树分为两类:
- 主工作树(Main Worktree) :通过
git init或git clone创建的原始目录。 - 链接工作树(Linked Worktree) :通过
git worktree add创建的额外工作目录。
关键约束:同一个分支在同一时刻只能在一个 worktree 中被检出,不能两个 worktree 同时指向同一分支。
二、核心命令速览
| 命令 | 说明 |
|---|---|
git worktree add <路径> [分支] |
创建新的链接工作树 |
git worktree list |
列出所有工作树 |
git worktree remove <路径> |
删除链接工作树 |
git worktree move <源> <目标> |
移动工作树到新路径 |
git worktree lock <路径> |
锁定工作树(防止被 prune 清理) |
git worktree unlock <路径> |
解锁工作树 |
git worktree prune |
清理失效的工作树元数据 |
git worktree repair |
修复工作树关联关系 |
三、使用案例
案例一:紧急线上 Bug 修复(最典型场景)
背景 :你正在 feature/user-profile 分支上开发新功能,代码写到一半,突然收到告警------线上 main 分支有严重 Bug 需要立即修复。
传统做法的痛点:
- 用
git stash暂存当前改动,切换到main分支修复,再切回来恢复现场,容易出错且打断思路。
使用 Worktree 的做法:
第一步:创建新工作树
bash
# 在终端执行,基于 main 分支在旁边创建一个新的工作目录
# 执行完成后 ../hotfix-workspace 里已有 main 分支的完整工作文件
git worktree add ../hotfix-workspace main
第二步:在 IDE 中打开新工作树目录
bash
# 终端进入新目录,并用 IDE 打开
cd ../hotfix-workspace
code . # VS Code:在新窗口打开 hotfix-workspace
# idea . # IntelliJ IDEA
# cursor . # Cursor
此时你有两个 IDE 窗口同时打开:
- 窗口 A:
my-project/,显示feature/user-profile分支,你写了一半的代码原封不动- 窗口 B:
hotfix-workspace/,显示main分支的干净代码,在这里做修复
第三步:在窗口 B 中完成 hotfix
bash
# 在 hotfix-workspace 目录的终端中执行
git checkout -b hotfix/critical-bug
# 在 IDE 窗口 B 中修改代码,完成后提交
git add .
git commit -m "fix: 修复线上支付金额计算错误"
git push origin hotfix/critical-bug
第四步:回到原来的工作
# 直接切回 IDE 窗口 A,my-project/ 里的一切完好如初
# 无需任何 git 操作,继续开发 feature/user-profile
第五步:清理工作树
bash
# 在任意目录的终端执行(hotfix-workspace 已无未提交改动)
git worktree remove ../hotfix-workspace
# hotfix-workspace 目录被删除,IDE 窗口 B 自动失效,关掉即可
优势:原分支的工作状态完全保留,无需 stash,两个 IDE 窗口可以同时打开并行工作,互不干扰。
案例二:多功能并行开发
背景 :你需要同时推进 feature/payment、feature/notification 两个功能,它们互相独立,希望能并行开发、随时切换。
为什么不能直接在两个分支之间来回切换?
表面上看,git checkout feature/payment 和 git checkout feature/notification 来回切换似乎可以解决问题,但实际开发中会遇到以下麻烦:
第一,切换分支前必须处理未提交的改动 。feature/payment 上改了一半的代码还没到提交的程度,这时要切到 feature/notification,Git 会直接拒绝,必须先 git stash 把改动压栈暂存,切换完再 git stash pop 恢复。两个功能来回切换,stash 栈越来越乱,一不小心就会 pop 错或产生冲突。
第二,切换分支会重置整个工作目录的文件。Git checkout 会把所有文件替换成目标分支的版本,IDE 感知到文件变化后会重新索引、重新编译,打开的标签页、调试断点、运行配置全部丢失,每次切换都要重新找回上下文,开发节奏被严重打断。
第三,无法真正并行 。同一个工作目录同一时刻只能对应一个分支,feature/payment 的本地服务和 feature/notification 的本地服务不能同时跑起来做对比。
使用 Worktree 的做法:为每个功能创建独立的工作目录,两个 IDE 窗口同时打开,各自的文件、进程、调试状态完全隔离,随时切换只需切换窗口。
bash
# 主工作树在 main 分支
# 为两个 feature 分别创建工作树,各自有一份独立的工作文件
git worktree add ../work-payment feature/payment
git worktree add ../work-notification feature/notification
# 查看当前所有工作树状态
git worktree list
# 输出示例:
# /Users/dev/my-project abc1234 [main]
# /Users/dev/work-payment def5678 [feature/payment]
# /Users/dev/work-notification ghi9012 [feature/notification]
# 在不同目录独立开发,互不干扰
cd ../work-payment
# ... 开发支付功能 ...
cd ../work-notification
# ... 开发通知功能 ...
# 开发完成后逐一清理
git worktree remove ../work-payment
git worktree remove ../work-notification
案例三:Code Review 时快速验证
背景 :同事提了一个 PR,分支名为 feature/new-search,你需要在本地跑起来验证效果,但不想污染自己当前的工作目录。
bash
# 先拉取远程分支
git fetch origin feature/new-search
# 创建一个临时工作树用于 Review
git worktree add /tmp/review-new-search origin/feature/new-search
cd /tmp/review-new-search
# 安装依赖、启动服务、验证功能
npm install && npm run dev
# Review 完成,删除临时工作树
git worktree remove /tmp/review-new-search
案例四:多版本并行维护
背景 :项目同时维护 v1.x、v2.x 两个大版本,需要分别修复 Bug 并发布补丁。
bash
# 为每个维护版本创建独立工作树
git worktree add ../project-v1 release/v1
git worktree add ../project-v2 release/v2
# 在 v1 目录修复 v1 的 Bug
cd ../project-v1
git checkout -b hotfix/v1-security-patch
# ... 修复 ...
git commit -m "fix: v1 安全漏洞修复"
# 在 v2 目录修复 v2 的 Bug
cd ../project-v2
git checkout -b hotfix/v2-security-patch
# ... 修复 ...
git commit -m "fix: v2 安全漏洞修复"
案例五:创建不关联任何分支的临时工作树
背景 :需要一个干净的工作区做实验,不想关联任何现有分支(使用 --detach 或孤立分支)。
bash
# 创建一个游离 HEAD 状态的工作树(基于某个 commit)
git worktree add --detach ../experiment-workspace HEAD
# 或者创建一个全新的孤立分支工作树
git worktree add --orphan -b experiment/sandbox ../sandbox-workspace
cd ../sandbox-workspace
# 随意实验,不影响任何分支
案例六:锁定工作树(防止误清理)
背景 :某个链接工作树挂载在可移动磁盘或网络路径上,担心 git worktree prune 因路径暂时不可达而误删元数据。
bash
# 锁定工作树,并附上说明原因
git worktree lock ../work-on-external-disk --reason "挂载在移动硬盘上,暂时不可用"
# 查看锁定状态
git worktree list --porcelain
# 输出中会显示 locked 字段
# 磁盘重新挂载后,解锁
git worktree unlock ../work-on-external-disk
案例七:清理失效的工作树
背景 :某个链接工作树的目录被手动删除(而不是通过 git worktree remove),导致 .git/worktrees/ 下残留了无效的元数据。
bash
# 查看当前工作树,发现有 prunable 状态的条目
git worktree list
# 预览将被清理的内容(不实际执行)
git worktree prune --dry-run
# 执行清理
git worktree prune
# 如果工作树目录被移动了,可以修复关联关系
git worktree repair ../new-location-of-worktree
四、与 git stash 的对比
| 对比维度 | git stash | git worktree |
|---|---|---|
| 切换成本 | 需要 stash → checkout → pop,步骤多 | 直接切换目录,零成本 |
| 并行工作 | 不支持,同一时刻只能在一个分支 | 支持,多目录同时工作 |
| 编辑器支持 | 只能打开一个工作目录 | 可同时在多个 IDE 窗口打开 |
| 磁盘占用 | 无额外占用 | 共享对象库,仅多一份工作文件 |
| 适用场景 | 短暂的临时切换 | 长期并行、多版本维护 |
五、注意事项
同一分支不能被两个 worktree 同时检出 。如果尝试这样做,Git 会报错:fatal: 'xxx' is already checked out。解决方法是先在另一个 worktree 中切换到其他分支,再在当前 worktree 检出目标分支。
删除工作树要用命令而非手动删除目录 。直接删除目录会导致 .git/worktrees/ 下残留元数据,需要后续用 git worktree prune 清理。
主工作树不能被 remove 。git worktree remove 只能删除链接工作树,主工作树是仓库本身,无法通过此命令删除。
工作树中有未提交改动时无法直接删除 。需要加 --force 参数强制删除,或先提交/丢弃改动再删除。
bash
# 强制删除含有未提交改动的工作树
git worktree remove --force ../dirty-worktree
cd 切换目录不等于切换编辑器视图 。在终端执行 cd ../hotfix-workspace 后,只有终端的工作目录发生了变化,VS Code、IDEA 等编辑器窗口仍然显示原目录的文件。需要在编辑器中手动打开新的工作树目录(code . / idea .),或者提前为每个工作树开一个独立的编辑器窗口,才能真正在对应分支的代码上进行编辑。
六、推荐目录结构
建议将所有链接工作树统一放在主仓库的同级目录,或使用专门的 .trees/ 子目录(需加入 .gitignore):
# 方式一:同级目录(推荐,路径清晰)
~/projects/
my-project/ ← 主工作树 (main)
my-project-hotfix/ ← 链接工作树 (hotfix/xxx)
my-project-v2/ ← 链接工作树 (release/v2)
# 方式二:子目录(集中管理)
~/projects/my-project/
.trees/
feature-payment/ ← 链接工作树
feature-notify/ ← 链接工作树
使用子目录方式时,记得在 .gitignore 中添加 .trees/,避免被 Git 追踪。