1. 什么是 Git Worktree?
传统 Git 切换分支时,工作区会完全覆盖当前文件。
Git Worktree 允许在同一个 Git 仓库中创建多个工作目录,每个工作目录可以独立地检出不同的分支。这意味着可以在一个仓库中同时处理多个任务,而不需要频繁地切换分支。实现:
- 并行开发:同时在不同分支写代码、运行测试
- 隔离环境:每个工作区独立编译/调试互不影响
- 零切换成本:无需 git stash 保存临时状态
2. 核心操作
1. 创建新工作区
场景:当前在 dev 分支,需紧急修复 hotfix 分支的 Bug。
bash
# 语法:git worktree add <路径> <分支名>
git worktree add ../hotfix-dir hotfix
效果:
- 在上级目录创建 hotfix-dir 文件夹
- 自动签出 hotfix 分支
- 原工作区保持 dev 分支不变
2. 查看当前仓库所有工作区
bash
git worktree list
输出示例:
bash
/path/main abcd123 [develop]
/path/hotfix-dir efgh456 [hotfix]
3. 删除工作区
bash
# 进入其他工作区操作
git worktree remove hotfix-dir
# 或强制删除未提交更改
git worktree remove --force hotfix-dir
注意:在删除工作树之前,请确保没有未提交的更改。
4. 举个 🌰
假设在开发一个项目,并且需要同时处理两个功能:feature/login 和 feature/signup。可以使用 git worktree 来创建两个独立的工作区。
1、创建主工作区
bash
git clone https://github.com/username/repo.git
cd repo
2、创建第一个工作树
bash
git worktree add ../login-feature feature/login
3、创建第二个工作树
bash
git worktree add ../signup-feature feature/signup
4、现在可以在 ../login-feature 和 ../signup-feature 目录中独立地工作。
3. 其他用法
- git worktree add [<options>] <path> [<branch>]:添加一个新的工作树。
- git worktree list [<options>]:列出所有的工作树。
- git worktree lock [<options>] <path>:锁定指定的工作树,防止其被删除。
- git worktree prune [<options>]:清理无效的工作树。
- git worktree unlock <path>:解锁之前锁定的工作树。
4. 性能对比 Worktree vs Clone
|---------|-----------------|-------------|
| 维度 | Worktree | Clone |
| 磁盘占用 | 共享对象库,节省 90% 空间 | 完全独立,占用双倍空间 |
| 分支切换速度 | 即时切换 | 需重新拉取全量历史 |
| 跨分支文件修改 | 允许同时修改不同分支的文件 | 独立仓库无法直接交互 |
| 适用场景 | 短期任务、紧急修复 | 长期独立开发、隔离实验 |
5. 注意事项
1、分支管理
每个工作树都可以检出不同的分支。如果在一个工作树中创建了新分支,确保在其他工作树中没有冲突。
2、未提交的更改
在删除工作树之前,请确保没有未提交的更改。未提交的更改不会被删除,但可能会导致混淆。
3、合并和冲突
如果在多个工作树中同时进行合并操作,可能会导致冲突。确保在合并之前解决所有冲突。
4、性能
使用 git worktree 可以提高工作效率,但请注意,多个工作树会占用更多的磁盘空间。
5、清理工作树
使用 git worktree prune 可以清理已经删除的工作树的引用。
6. 底层原理
Git 的 worktree 机制允许在同一个仓库中同时检出多个分支,每个工作树(worktree)有独立的工作目录,但共享底层对象数据库和仓库元数据。它的底层设计通过以下几个关键部分实现:
1. 文件系统结构
1)主仓库的 .git 目录
主仓库的 .git 目录中有一个 worktrees 子目录,用于管理所有附加工作树的元数据:
bash
.git/
├── worktrees/
│ ├── worktree1/ # 每个工作树对应一个子目录
│ │ ├── HEAD # 当前工作树的检出位置(如分支或提交)
│ │ ├── index # 该工作树的暂存区(索引)
│ │ ├── locked # 如果存在,表示工作树被锁定
│ │ └── commondir # 指向主仓库的 .git 目录(共享对象库)
│ └── worktree2/ # 另一个工作树的元数据
└── ...
2)工作树的 .git 文件
每个附加工作树的根目录下有一个 .git 文件(不是目录),其内容指向主仓库的对应元数据目录:
bash
gitdir: /path/to/main/repo/.git/worktrees/worktree1
这个文件告诉 Git 如何找到该工作树的元数据(如 HEAD、索引等)。
2. 共享与隔离
1、共享对象数据库
- 所有工作树共享主仓库的 对象数据库(.git/objects),因此在不同工作树中创建的提交、分支等会同步到同一仓库。
- 避免了克隆多个仓库的开销,节省磁盘空间。
2、隔离的工作状态
- 独立的 HEAD 和索引:每个工作树有自己的 HEAD 和 index 文件,因此可以同时在不同分支上工作。
- 独立的配置文件:可以通过 git config extensions.worktreeConfig true 启用工作树特定的配置(默认共享主仓库配置)。
3. 元数据同步
1、分支和引用
- 所有工作树的引用(如分支、标签)存储在共享的 .git/refs 目录中。
- 如果两个工作树同时操作同一分支,Git 会通过锁机制(如 .git/refs/heads/<branch>.lock)避免冲突。
2、锁机制
- 执行某些操作时(如切换分支),Git 会在元数据目录中创建 locked 文件,防止并发修改。
- 手动删除 locked 文件可以强制释放锁(需谨慎操作)。
4. 工作树生命周期管理
- 添加工作树
执行 git worktree add 时:
- 在 .git/worktrees 中创建新的元数据目录。
- 在工作树路径下生成 .git 文件。
- 检出指定分支或提交到该工作树。
2)清理无效工作树
- git worktree prune 会扫描 .git/worktrees,删除指向无效路径的元数据。
- 手动删除工作树目录后,必须运行此命令清理残留数据。
Git 工作树通过 元数据隔离 和 对象共享 的机制,在单一仓库中实现多工作目录的并行操作。
掌握 worktree 后,将彻底告别「单分支开发」的原始模式,进入 Git 高效协作的新场景。