Git Worktree 实现 “一边修生产Bug,一边写新需求”

发布于:2025-03-20 ⋅ 阅读:(23) ⋅ 点赞:(0)

1. 什么是 Git Worktree?

传统 Git 切换分支时,工作区会完全覆盖当前文件。

Git Worktree 允许在同一个 Git 仓库中创建多个工作目录,每个工作目录可以独立地检出不同的分支。这意味着可以在一个仓库中同时处理多个任务,而不需要频繁地切换分支。实现:

  • 并行开发:同时在不同分支写代码、运行测试
  • 隔离环境:每个工作区独立编译/调试互不影响
  • 零切换成本:无需 git stash 保存临时状态

2. 核心操作

1. 创建新工作区

场景:当前在 dev 分支,需紧急修复 hotfix 分支的 Bug。

# 语法:git worktree add <路径> <分支名>
git worktree add ../hotfix-dir hotfix

效果:

  • 上级目录创建 hotfix-dir 文件夹
  • 自动签出 hotfix 分支
  • 原工作区保持 dev 分支不变
2. 查看当前仓库所有工作区
git worktree list

输出示例:

/path/main       abcd123 [develop]
/path/hotfix-dir efgh456 [hotfix]
3. 删除工作区
# 进入其他工作区操作
git worktree remove hotfix-dir
# 或强制删除未提交更改
git worktree remove --force hotfix-dir

注意:在删除工作树之前,请确保没有未提交的更改。

4. 举个 🌰

假设在开发一个项目,并且需要同时处理两个功能:feature/login 和 feature/signup。可以使用 git worktree 来创建两个独立的工作区。

1、创建主工作区

git clone https://github.com/username/repo.git
cd repo

2、创建第一个工作树

git worktree add ../login-feature feature/login

3、创建第二个工作树

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 子目录,用于管理所有附加工作树的元数据:

.git/
├── worktrees/
│   ├── worktree1/   # 每个工作树对应一个子目录
│   │   ├── HEAD     # 当前工作树的检出位置(如分支或提交)
│   │   ├── index    # 该工作树的暂存区(索引)
│   │   ├── locked   # 如果存在,表示工作树被锁定
│   │   └── commondir  # 指向主仓库的 .git 目录(共享对象库)
│   └── worktree2/   # 另一个工作树的元数据
└── ...

2)工作树的 .git 文件

每个附加工作树的根目录下有一个 .git 文件(不是目录),其内容指向主仓库的对应元数据目录:

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. 工作树生命周期管理

1) 添加工作树

执行 git worktree add 时:

  1. 在 .git/worktrees 中创建新的元数据目录。
  2. 在工作树路径下生成 .git 文件。
  3. 检出指定分支或提交到该工作树。

2)清理无效工作树

  1. git worktree prune 会扫描 .git/worktrees,删除指向无效路径的元数据。
  2. 手动删除工作树目录后,必须运行此命令清理残留数据。

Git 工作树通过 元数据隔离对象共享 的机制,在单一仓库中实现多工作目录的并行操作。

掌握 worktree 后,将彻底告别「单分支开发」的原始模式,进入 Git 高效协作的新场景。