Git Worktree 详解
Git worktree(工作树)允许你在同一份仓库 中同时检出多个分支到不同的目录,无需反复切换分支或克隆多份仓库。这是处理并行任务(多分支开发、热修复、代码评审)的利器。
为什么需要 worktree?
普通 Git 工作流的痛点:
- 切换分支成本高 :
git checkout会暂停当前工作,未提交的修改会阻塞切换或带来冲突。 - 并行需求冲突:想在 A 分支写功能,又想马上切到 B 分支修 bug,如果依赖未提交内容就会互相干扰。
- 克隆多份仓库占用空间大 :
git clone会把整个.git历史复制多份,磁盘和索引损耗都很大。
worktree 的解决方案 :共享同一份仓库历史(同一个 .git 目录),但每个 worktree 有独立的工作目录 + 暂存区 + HEAD。你可以同时打开多个目录,分别处于不同分支,互不阻塞。
核心概念
- main worktree(主工作树):默认的一棵工作树,通常对应仓库根目录。
- linked worktree(链接工作树) :通过
git worktree add额外检出的工作树,位于其他目录。 .git目录共享:所有 worktree 共享同一份对象库(objects)、引用(refs)、配置(config),因此切换成本极低。
目录结构说明
project/
├── .git/ # 共享:对象库、refs、config(整个仓库唯一的 .git)
├── index.html # main worktree(主工作树 / 当前分支)
└── _feature/ # linked worktree(另一个分支)
├── .git # 这是一个文件,内容指向共享 .git 目录
└── index.html # feature 分支的文件
链接 worktree 里的
.git不是目录,而是一个文本文件,内容形如:
gitdir: /path/to/project/.git/worktrees/_feature这就是所有 worktree 共享同一份历史的关键。
常用命令速查
| 操作 | 命令 |
|---|---|
| 查看所有 worktree | git worktree list |
| 新建 worktree(新分支) | git worktree add <目录> -b <新分支名> [基点] |
| 新建 worktree(检出已存在分支) | git worktree add <目录> <已存在分支> |
| 基于某个 commit/tag 创建 | git worktree add <目录> <commit/tag> |
| 从临时分支创建 | git worktree add --detach <目录> <commit> |
| 移动 worktree | git worktree move <旧目录> <新目录> |
| 锁定 worktree | git worktree lock <目录> |
| 解锁 worktree | git worktree unlock <目录> |
| 清理已删除分支的 worktree 记录 | git worktree prune |
| 删除 worktree | git worktree remove <目录> |
经典使用场景
1. 并行多分支开发
# 在 main 工作树基于 master 开一个功能分支的工作树
git worktree add ../project-feature -b feature/new-ui
# 在另一个目录并行做热修复
git worktree add ../project-hotfix -b hotfix/login-bug
# 三个目录互不干扰,都指向同一个仓库
git worktree list
2. 边开发边代码评审
# 检出同事的 PR 分支,不影响你当前正在写的代码
git worktree add ../review -b review/branch-name origin/pr-branch
3. 快速尝试验证某个版本
# 临时查看某个 tag/commit,不想动当前分支
git worktree add --detach ../tmp-v2.0 v2.0
# 用完即删
git worktree remove ../tmp-v2.0
使用注意事项
一个分支只能有一个 worktree
同一分支在同一仓库中只能被一个 worktree 检出。 若已有一棵 worktree 在 feature/x 上,再 git worktree add ../t2 feature/x 会报错:
fatal: 'feature/x' is already checked out at '...'
这是为了确保对一个分支的提交方向是唯一的。
删除前先检查是否干净
git worktree remove 默认拒绝删除有未提交改动或未跟踪文件的 worktree,需先清理或加 --force(谨慎)。
分支删除后残留的记录
分支被删除后,其 worktree 相关记录仍存在。定期执行 git worktree prune 清理。
暂存区相对独立
每个 worktree 有独立的暂存区(index)。在 A worktree 暂存的改动不会出现在 B worktree。
完整练习:从 0 上手
# 1. 创建演示仓库
mkdir demo-worktree && cd demo-worktree
git init -b main
echo "hello" > README.md && git add . && git commit -m "init"
# 2. 查看当前 worktree(只有 main)
git worktree list
# demo-worktree <hash> [main]
# 3. 创建功能分支的 worktree
git worktree add ../demo-wt-feature -b feature/hello
# 4. 进入新 worktree 写代码
cd ../demo-wt-feature
echo "world" >> README.md
git commit -am "update from feature worktree"
# 5. 回到主 worktree,main 分支完全没受影响
cd ../demo-worktree
git log --oneline # 仍只有 init
# 6. 删除 worktree 并清理
cd ..
git worktree remove --force ../demo-wt-feature
git branch -d feature/hello
git -C demo-worktree worktree prune
高级技巧
给 worktree 配置不同远程
可以将不同 worktree 指向不同远程,便于发布/测试:
git worktree add ../prod -b release/prod
git -C ../prod remote add prod git@example.com:prod-repo.git
git -C ../prod fetch prod
用 shell 别名加速
# ~/.bashrc 或 ~/.zshrc
alias wt-add='git worktree add'
alias wt-list='git worktree list'
alias wt-rm='git worktree remove'
alias wt-prune='git worktree prune'
在 worktree 间跳转
# 列出后,用 -C 直接到对应目录执行 git
git worktree list
git -C ../project-feature status
常见问题(FAQ)
Q:worktree 会重复占用磁盘空间吗?
A:不会重复保存历史对象。所有 worktree 共享同一 .git 对象库,只额外占一份工作目录 + 暂存区的空间。
Q:可以嵌套多个 worktree 吗?
A:可以,git worktree add 可重复创建任意多棵,只要目录不冲突、分支不重复检出。
Q:worktree 里的分支能 push 吗?
A:能,它就是一份正常的 Git 检出,push/pull/fetch 都照常工作。
Q:误删了 worktree,还能找回吗?
A:分支和提交仍保留在仓库历史里,可用 git branch 重建分支后重新 git worktree add 检出。
Q:不同 worktree 之间能合并吗?
A:能,本质是不同分支,在该仓库任意 worktree 中 git merge 或 git rebase 即可。
总结
| 场景 | 是否建议用 worktree | 替代方案 |
|---|---|---|
| 并行开发多个功能 | ✅ 强烈推荐 | 多份 clone(费空间) |
| 频繁切换分支写代码 | ✅ 推荐 | git stash + checkout |
| 边写边评审他人 PR | ✅ 推荐 | 切分支 / stash |
| 只是想看旧版本 | ✅ 适合 | git show |
| 一次性实验 | 一般 | 临时 clone / stash |
一句话记忆 :git worktree 用「一份历史、多份工作目录」解决「多任务并行」。