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 list2. 边开发边代码评审
# 检出同事的 PR 分支,不影响你当前正在写的代码 git worktree add ../review -b review/branch-name origin/pr-branch3. 快速尝试验证某个版本
# 临时查看某个 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用「一份历史、多份工作目录」解决「多任务并行」。