[转载] 用 Git worktree 做并行开发,不再手忙脚乱


原文出处: https://barrd.dev/article/parallel-development-without-the-headaches-using-git-worktree/
作者: Dave(barrd)
原文发布日期: 2026-01-01
许可协议: 本文为其中文翻译,所有权利归原文作者所有。


引言

最近在折腾一个相当棘手的项目时,我接触到了 Git 的 worktree 功能。它让你可以同时在多个分支上工作,每个分支各自拥有一个目录,而它们共享同一套底层仓库历史。

一个直观的示意:

~/Herd/
├── my-project/          # 主 worktree,分支 `main`
│   └── .git/            # 主 git 目录
├── my-project-feature/  # 链接 worktree,分支 `feature/login-form`
└── my-project-hotfix/   # 链接 worktree,分支 `hotfix/payment-bug`

上面这些目录共享同一份提交历史,并且都链接到同一个 .git 对象数据库,尽管每个目录都有各自独立的工作区状态。

每个目录的行为都和一个普通 checkout 一样:照常编辑文件、提交、推送,只是不必再在单一工作区里不停地切换分支。

Git branch 与 worktree 的区别

传统上,在多个分支间切换意味着大量的 git checkoutgit stash——不停保存现场、切换上下文,还得祈祷没弄丢什么重要的东西。这很容易迷失,尤其是当生产环境的 bug 打断你的思路时。有了 git worktree,你可以为任意分支(已有的或新建的)添加一个新工作目录,让各条工作流互不干扰。比如:

# 把已有分支添加为 worktree
git worktree add ../my-project-feature feature-branch

# 或者一步创建新分支 + worktree
git worktree add -b new-feature ../my-project-new-feature

这会在主项目同级的位置创建新目录,并 checkout 到你指定的分支。现在你可以在每个目录里独立地编辑、提交、推送,完全不影响主工作目录。

你的目录布局大概会是这样:

my-project/              # 主 worktree,分支 `main`
my-project-feature/      # worktree,分支 `feature-branch`
my-project-new-feature/  # worktree,分支 `new-feature`

一个重要的限制:同一个分支不能同时被多个 worktree checkout。每个 worktree 必须检出不同的分支。实际使用中,这反而促成一种清爽的心智模型——「一个任务、一个分支、一个目录」,让人不容易迷失方向。

实战示例:功能开发和紧急修复两头兼顾

来看一个真实场景:你正在开发一个结账功能,这时生产环境的 bug 突然冒出来了。

初始布局:

~/Herd/
└── shop/           # 主 worktree,分支 `main`
    └── .git/

创建功能分支的 worktree:

cd ~/Herd/shop
git worktree add -b feature/checkout ../shop-checkout

新布局:

~/Herd/
├── shop/           # 主 worktree,分支 `main`
│   └── .git/
└── shop-checkout/  # 链接 worktree,分支 `feature/checkout`

接下来你可以在 shop-checkout 里安心开发结账功能,同时让 shop 停在 main 上,随时可以用来做快速审查。

生产环境出 bug 了,建一个 hotfix worktree

cd ~/Herd/shop
git worktree add -b hotfix/payment-fail ../shop-payment-hotfix

目录布局变成:

~/Herd/
├── shop/                 # 主 worktree,分支 `main`
├── shop-checkout/        # 功能 worktree,`feature/checkout`
└── shop-payment-hotfix/  # hotfix worktree,`hotfix/payment-fail`

此时你可以:

如何把 worktree 的分支合并到其他分支

从 worktree 分支发起合并,和普通的 Git merge 没有任何区别,只是上下文更清晰,因为每个分支都住在自己的目录里。下面是把功能分支合入 main 的典型流程:

  1. 在功能 worktree 里完成工作并提交。
  2. 切换到主 worktree 目录:
cd ../my-project && git checkout main
  1. 合并功能分支:
git merge feature-branch
  1. 解决冲突(如果有),然后推送。

正因为每个 worktree 都专属于一个分支,你很难再把提交落错分支,也不至于在 hotfix 打断功能开发时丢了现场……当然,这是理论上的。😉

查看当前的 worktree

在开始删除或清理之前,先看看 Git 目前都知道哪些 worktree:

git worktree list

示例输出:

/Users/barrd/Herd/shop                 66c16256 [main]
/Users/barrd/Herd/shop-checkout        0c8ba118 [feature/checkout]
/Users/barrd/Herd/shop-payment-hotfix  a16e4be2 [hotfix/payment-fail]

你可以在脑中把它映射成:

[main]                → /home/user/Herd/shop
[feature/checkout]    → /home/user/Herd/shop-checkout
[hotfix/payment-fail] → /home/user/Herd/shop-payment-hotfix

哪些分支被检出、检出到哪里,一目了然,也能避免去复用一个已被其他 worktree 占用的分支。

如何删除 worktree

一个 worktree 用完之后,最好及时清理。安全删除的前提是先提交或 stash 掉所有改动:

git worktree remove ../my-project-feature

只有干净的工作树(没有未提交改动、没有未跟踪文件)才能这样删除,除非加 --force;主 worktree 则永远无法被移除。

记住
删除 worktree 只是删掉工作目录,分支本身还在。删除前务必在该 worktree 里 git status 确认一下,以免弄丢未提交的工作。

用 prune 清理失效的 worktree

如果你是手动 rm 掉了 worktree 目录,Git 仍会在主仓库的 worktrees 目录下保留它的元数据。这时 git worktree list 会把对应条目标记为缺失。

清理这些失效条目:

git worktree prune

如果只想清理一段时间未使用的条目,可以加过期时间:

git worktree prune --expire 7.days.ago

--expire now 则立即清除所有失效元数据——如果你在本地开发环境里经常随手清掉旧目录,这招会很顺手。

写在最后

worktreev2.5(大约 10 年前)起就已存在,而我从来没用过……但现在它彻底改变了我的工作流,尤其是在并行推进多个功能和应对紧急 hotfix 的时候。一切都各归其位,上下文切换减少了,stash 也成了罕物。

对于简单的、串行推进的工作,传统分支方式依然是首选;但如果你曾幻想自己能同时身处两地,不妨试试 git worktree