用途
git worktree 是 Git 提供的一项功能,用于在同一个仓库上创建额外的工作目录。每个仓库初始只有一个工作树(主工作树),通过 git worktree add 可以添加链接工作树。所有工作树共享同一个 .git 对象库、引用(分支、标签)、配置、钩子、远程跟踪信息和 rerere 缓存;但每个工作树拥有独立的工作区文件、索引(暂存区)、HEAD、MERGE_HEAD、REBASE_HEAD、CHERRY_PICK_HEAD、.env 文件、node_modules 和构建产物。
主工作树由 git init 或 git clone 创建,无法通过 git worktree remove 删除;链接工作树可以自由添加和删除。内部实现上,每个链接工作树在 .git/worktrees/<name>/ 下拥有自己的 HEAD、索引和跟踪文件,其工作目录中的 .git 是一个指向该位置的文本文件而非目录。
主要能力
- 从已有分支创建工作树:git worktree add ../hotfix-login hotfix/login
- 从新分支创建工作树:git worktree add -b feature/search ../feature-search main
- 从特定提交创建(分离 HEAD):git worktree add --detach ../investigate-crash abc1234
- 从远程分支创建:先 git fetch origin,再 git worktree add ../review-pr42 origin/pr-42
- 列出工作树:git worktree list(加 --porcelain 输出机器可读格式)
- 移除工作树:git worktree remove ../hotfix-login(--force 可丢弃未提交更改)
- 移动工作树:git worktree move ../hotfix-login ../hotfix-auth
- 锁定/解锁:git worktree lock ../usb-worktree --reason "on external drive" 与 git worktree unlock ../usb-worktree
- 清理失效条目:git worktree prune(可先 --dry-run 预览)
使用方式
与 stash、分支切换、克隆相比,worktree 适合并行工作并保持多个上下文存活。stash 适合 5 分钟内的快速中断,但会导致线性工作流和 stash 堆积;分支切换要求工作区干净;克隆则完全隔离但会复制对象库。worktree 共享对象库,在 2 GB 历史的仓库上,第二个工作树仅占用工作区文件大小,而第二个克隆需要 2 GB 加工作区。分支和标签在所有工作树间即时更新,钩子和配置也共享。
目录布局推荐同级目录(如 ~/projects/myapp、myapp-hotfix、myapp-review)或子目录布局配合裸仓库模式。裸仓库模式通过 git clone --bare 创建无默认工作树的仓库,再为各分支创建工作树,避免默认分支已被检出的问题。
常见工作流包括:功能开发中途紧急热修复、工作区脏时审查 PR、一个分支编码另一个分支跑测试、并排比较不同分支行为。每个工作树有独立的 node_modules、dist、build、.env 和生成文件,需要独立运行安装命令;构建缓存不共享。子模块不会自动初始化,需在每个新工作树中运行 git submodule update --init --recursive。
CI/CD 中可在单个任务内测试多个分支,无需多次克隆。IDE 方面,VS Code 用 code ../myapp-hotfix 打开新窗口,JetBrains 通过 File > Open 打开工作树目录,Vim/Neovim 直接 cd 进入即可,任何能打开文件夹的编辑器都无需特殊配置。
适用场景
- 并行开发多个分支,保持各自未提交的上下文
- 生产环境故障时快速创建热修复工作树
- 审查 PR 而不影响当前进行中的工作
- 在一个分支编码的同时在另一个工作树运行测试
- 并排运行不同分支的应用进行行为对比
- CI 中并行测试多个分支,节省时间和磁盘
- 裸仓库配合工作树管理多个分支的检出
- dotfiles 管理
限制
- 同一分支不能在两个工作树中同时检出,Git 会阻止;可用 --detach 或临时分支绕过
- 每个工作树需要独立安装依赖,构建缓存不共享
- 直接删除目录而不使用 git worktree remove 会留下孤立条目,需用 git worktree prune 清理
- git gc 影响所有工作树,激进修剪可能移除其他工作树索引仍引用的对象
- git config 默认写入共享配置,需启用 extensions.worktreeConfig 后使用 git config --worktree 实现每工作树配置
- 主工作树无法移动或移除
- 工作树不自动初始化子模块
- 额外磁盘空间占用(工作区文件)