Git Worktree 简明指南

# Git Worktree 简明指南

> `git worktree` 的核心作用:**一个 Git 仓库,同时开出多个独立工作目录**。每个目录可以停在不同分支,互不打断,适合并行开发、紧急修 bug、PR review、跑多个 agent。

---

## Level 1 · 它到底解决什么问题

普通 Git 工作流里,一个仓库目录一次只能检出一个分支:

```bash
cd my-project
git switch main
# 或
git switch feature/payment
```

如果你正在 `feature/payment` 上改到一半,突然要修线上 bug,就会遇到三件麻烦事:

1. 当前改动还没提交
2. 不能直接切分支
3. 只能先 `stash`,修完再 `stash pop`

典型流程会变成:

```bash
git stash
git switch main
git switch -c fix/login-bug
# 修 bug
git switch feature/payment
git stash pop
```

这不是不能用,但会严重打断思路。

`git worktree` 的思路是:**不要在同一个目录里反复切分支,而是给每个任务一个目录。**

例如:

```text
~/code/my-project/                  # main
~/code/my-project-feature-payment/  # feature/payment
~/code/my-project-fix-login/        # fix/login-bug
```

它们共享同一个 Git 仓库历史,但工作目录彼此独立。

---

## Level 2 · 先看有哪些 worktree

在任意一个 worktree 里执行:

```bash
git worktree list
```

示例:

```text
/home/me/code/my-project                  abc1234 [main]
/home/me/code/my-project-feature-payment  def5678 [feature/payment]
/home/me/code/my-project-fix-login        9988776 [fix/login-bug]
```

每一行大概是:

```text
路径                                  当前 commit   当前分支
```

这条命令很重要。只要你忘了自己开过哪些目录,先执行它。

---

## Level 3 · 基于已有分支创建 worktree

如果远程或本地已经有一个分支:

```bash
feature/payment
```

可以创建一个对应的工作目录:

```bash
git worktree add ../my-project-feature-payment feature/payment
```

格式是:

```bash
git worktree add <新目录路径> <分支名>
```

然后进入新目录:

```bash
cd ../my-project-feature-payment
git branch --show-current
```

输出应该是:

```text
feature/payment
```

从这里开始,你就像在普通仓库里一样开发、提交、推送。

---

## Level 4 · 创建 worktree 的同时新建分支

更常见的场景是:从 `main` 开一个新分支,并放进新 worktree。

```bash
git worktree add -b fix/login-bug ../my-project-fix-login main
```

格式是:

```bash
git worktree add -b <新分支名> <新目录路径> <基于哪个分支>
```

这条命令等价于三件事:

1. 从 `main` 创建 `fix/login-bug`
2. 创建目录 `../my-project-fix-login`
3. 把 `fix/login-bug` 检出到这个目录

进入新目录:

```bash
cd ../my-project-fix-login
```

确认分支:

```bash
git branch --show-current
```

---

## Level 5 · 一个完整日常流程

假设主仓库在:

```bash
~/code/my-project
```

你要修一个登录 bug。

### 1. 主目录保持在 main

```bash
cd ~/code/my-project
git switch main
git pull
```

### 2. 创建 bugfix worktree

```bash
git worktree add -b fix/login-error ../my-project-fix-login-error main
```

### 3. 进入新目录开发

```bash
cd ../my-project-fix-login-error
```

修改代码,跑测试,然后提交:

```bash
git status
git add .
git commit -m "fix: handle login error correctly"
```

### 4. 推送分支

```bash
git push -u origin fix/login-error
```

然后正常创建 PR。

### 5. PR 合并后清理

先回到别的目录,不要站在要删除的 worktree 里面删自己:

```bash
cd ~/code/my-project
```

删除 worktree:

```bash
git worktree remove ../my-project-fix-login-error
```

删除本地分支:

```bash
git branch -d fix/login-error
```

如果远程分支也要删:

```bash
git push origin --delete fix/login-error
```

---

## Level 6 · 推荐目录结构

推荐把 worktree 放在主仓库同级目录,而不是主仓库内部。

推荐:

```text
~/code/
  my-project/                    # main
  my-project-feature-payment/     # feature/payment
  my-project-fix-login/           # fix/login-bug
  my-project-review-123/          # review PR #123
```

不太推荐:

```text
~/code/my-project/
  worktrees/
    fix-login/
```

原因很简单:放在仓库内部,编辑器、搜索、构建工具、测试工具可能会把里面的文件也扫进去,容易混乱。

目录名最好带上任务含义:

```bash
my-project-fix-login
my-project-feature-payment
my-project-refactor-auth
my-project-review-pr-123
```

不要叫:

```bash
test
new
tmp
copy
```

几天后你会完全忘记它们是什么。

---

## Level 7 · 删除和清理

正常删除:

```bash
git worktree remove ../my-project-feature-payment
```

如果目录里还有未提交改动,Git 会阻止删除。

先检查:

```bash
cd ../my-project-feature-payment
git status
```

确认真的不要了,再强制删除:

```bash
git worktree remove --force ../my-project-feature-payment
```

如果你曾经手动删过目录:

```bash
rm -rf ../my-project-old-task
```

Git 可能还留着一条过期记录。清理它:

```bash
git worktree prune
```

再看列表:

```bash
git worktree list
```

---

## Level 8 · 常见坑

### 1. 同一个分支不能同时被两个 worktree 使用

如果 `main` 已经在主目录里被检出:

```text
~/code/my-project  [main]
```

再执行:

```bash
git worktree add ../my-project-main-copy main
```

可能会报错:

```text
fatal: 'main' is already checked out
```

这是正常限制:同一个分支默认不能同时在两个 worktree 里检出。

如果只是想临时看一下 `main` 的内容,可以用 detached 模式:

```bash
git worktree add --detach ../my-project-main-copy main
```

但日常开发不要长期在 detached 状态下工作,容易忘记提交落在哪个分支上。

### 2. 不要直接 `rm -rf` 删除 worktree

优先用:

```bash
git worktree remove <path>
```

它会同时清理 Git 内部记录。

如果已经手动删了,再补:

```bash
git worktree prune
```

### 3. 先确认当前目录和分支

worktree 多了以后,最容易搞错的是:人以为自己在 A 任务,实际终端停在 B 目录。

动手前养成习惯:

```bash
pwd
git branch --show-current
git status
```

---

## Level 9 · 和 clone、stash 的区别

### worktree vs clone

你也可以重新 clone 一份仓库:

```bash
git clone git@github.com:xxx/my-project.git my-project-copy
```

但 clone 是完整复制一份仓库。

`worktree` 是在同一个仓库对象库上开多个工作目录,更轻量,也更适合本机并行分支开发。

| 方式 | 特点 |
|---|---|
| `git clone` | 完整复制一份仓库,彼此更独立 |
| `git worktree` | 共享同一份 Git 历史,只增加工作目录 |

### worktree vs stash

| 场景 | 更适合 |
|---|---|
| 临时切一下分支,改动很少 | `git stash` |
| 同时长期处理多个任务 | `git worktree` |
| 紧急 bugfix,不想打断当前开发 | `git worktree` |
| 同时跑两个分支的项目 | `git worktree` |
| 多个 agent 并行改同一个仓库 | `git worktree` |

一句话:

> `stash` 是把当前改动临时收起来;`worktree` 是给另一个任务直接开一张新桌子。

---

## Level 10 · Agent 场景下为什么常见

很多 coding agent 会用 worktree 做隔离。

根本原因是:如果两个 agent 同时在同一个目录里改文件,它们会互相冲突。一个 agent 改到一半,另一个 agent 也改同一个文件,工作区很快就乱了。

用 worktree 后,可以变成:

```text
repo-agent-task-a/  # agent A 的分支
repo-agent-task-b/  # agent B 的分支
repo-agent-review/  # review 分支
```

它们共享历史,但文件系统层面互不干扰。每个 agent 在自己的目录里工作,最后通过 Git merge / rebase / PR 来合并结果。

所以在多 agent、后台任务、自动修 CI、并行实验这些场景里,worktree 是很自然的基础设施。

---

## 常用命令速查

查看所有 worktree:

```bash
git worktree list
```

基于已有分支创建 worktree:

```bash
git worktree add ../my-project-feature feature/payment
```

创建 worktree 的同时新建分支:

```bash
git worktree add -b feature/payment ../my-project-feature-payment main
```

删除 worktree:

```bash
git worktree remove ../my-project-feature-payment
```

强制删除:

```bash
git worktree remove --force ../my-project-feature-payment
```

清理过期记录:

```bash
git worktree prune
```

查看当前分支:

```bash
git branch --show-current
```

---

## 最小心智模型

记住三句话就够了:

1. `git worktree` 让一个仓库同时拥有多个工作目录。
2. 每个 worktree 通常对应一个分支,适合一个任务一个目录。
3. 创建用 `git worktree add`,结束用 `git worktree remove`,别直接 `rm -rf`。

最常用的命令是:

```bash
git worktree add -b <branch> <path> <base>
git worktree list
git worktree remove <path>
```

如果你经常在多个分支之间来回切,或者需要并行处理多个任务,worktree 通常比反复 `checkout` + `stash` 更清楚。