告别 Git 切换痛苦:Git worktree 并行开发指南

Parallel development without the headaches using Git worktree

告别 Git 切换痛苦:Git worktree 并行开发指南

最近在处理棘手项目时,我发现了 Git 的 worktree 功能,它彻底改变了我并行开发的工作流。过去,同时处理多个分支意味着频繁使用 git checkout 和 git stash,不仅容易丢失上下文,还可能在生产故障出现时打断思路。现在,我可以在不同目录中为 feature/login-form 或 hotfix/payment-bug 创建独立的 worktree,每个目录对应一个分支,共享同一个 Git 仓库历史。这样,我既能专注于新功能开发,又能随时切换到紧急修复,无需担心代码冲突或丢失未提交的更改。这种“一个任务、一个分支、一个目录”的模式,让开发过程更加清晰高效,stashing 几乎成了历史。如果你也曾在多个分支间疲于奔命,不妨试试 Git worktree,它或许能成为你日常开发中的得力助手。

如果你发现自己希望同时身处两个地方,不妨试试 Git worktree。
  1. tlarkworthy

    我使用一个顶层元仓库来创建一个包含所有仓库的虚拟 monorepo,并引入它们的上游依赖,然后利用子模块的 worktree 来准备补丁。即使有多个代理(agents)在运行,我也无需从根元仓库切换目录。这让你获得了完整的 monorepo 体验,却无需实际拥有任何部分;每个代理都有自己隔离的 worktree,因此不会发生冲突。

  2. zmmmmm

    并行开发真正的难题在于,确保并行开发环境能够无缝共存,互不干扰。一旦其中一个环境需要打开端口、连接外部数据库或写入共享位置作为测试的一部分,它们就会相互冲突。

    这很大程度上是一个遗留的开发问题:过去从未假设会有如此多的并行临时开发环境同时运行。但遗留开发模式目前仍是开发的主流。

  3. therealmarv

    也许我只是固执,但在 AI 时代,我仍然为同一个项目使用多个 git 克隆/目录,例如:

    ~/dev/projectx

    ~/dev/projectx2

    ~/dev/projectx3

    ~/dev/projectx4

    每个项目很少超过 4–5 个。也许我只是在回避去理解 worktrees 并真正尝试它们。

    好处是:这些克隆充当了半永久目录:

    - 有助于重度 Docker 使用的缓存(想想重复的并行单元测试、e2e 测试)

    - 我为每个克隆的终端标签页设置了颜色编码,这样一眼就能看出我在哪个目录(有点像带颜色的标签组)

    也许如果出于某种原因我需要双位数的克隆,我会更被迫使用 git worktrees,因为那时记住某个分支克隆在哪个目录下会变得很烦人。

  4. irskep

    我每天都在使用 git worktrees。令我惊讶的是,向从未用过的人解释它们竟然这么难。最近我总结为:“就像克隆一样,但共享一个 .git 目录。”这篇文章试图通过将其与分支比较来传达这个概念,但我认为与克隆比较更直观。

    为了解决一些易用性问题(命令冗长、手动复制 .env 文件和安装依赖),我编写了 autowt,这是一个轻量但功能强大的 worktree 管理器:https://steveasleep.com/autowt/

    一旦我调优了 CLI 体验,我基本上就不再输入 'git checkout <branch>' 来切换任务了,因为在切换任务时,忽略工作目录状态要容易得多。

  5. pkghost

    在 worktree 这个兔子洞里钻了一个月左右后,我决定放弃,转而使用多个 checkout,以便让多个代理(agents)在多个仓库上协同工作。

    当我的代理工作主要局限于单个仓库时,worktree 对我非常有效(它们让我最终触发了速率限制,虽然那并非我的目标)。随着我的 homelab 扩展,代理越来越多地在多个仓库间工作,而这就是(我使用)worktree 失败的地方:代理在仓库的 worktree 中启动,因此无需特殊指令就能避免与同一仓库中的其他代理冲突;但一旦它们需要操作另一个仓库,就会默认直接在该仓库中工作,而不使用 worktree,从而与其他代理发生冲突,并弄脏了原本期望主仓库克隆保持干净的合并流程(事实证明这是一个不必要的设计怪癖,但解决这个问题仍然无法阻止代理在次要仓库中互相踩脚)。

    在尝试了 ZFS 数据集克隆和一些挂载魔术(让 /srv/src/ 对每个代理进程看起来像是一个独立的层次结构)之后,我进一步简化,给每个代理一个裸目录(类似 /srv/dev/<slug>/),它们可以在其中 checkout 任何想要的仓库。git remote (/srv/git/) 成为了唯一的集成点。

    也许我应该干脆咬咬牙转向容器,但尽管它们性能很好,易用性仍然让我很头疼。

    编辑:我可能会保留带有 mou 的 ZFS 数据集 […]

同日更多故事

2026-08-24