关于git worktree正确使用姿势的思考

Git Worktree:多工作目录的高效开发模式

worktree 提供了一种在使用相同 .git 文件夹的情况下,实现多工作目录的能力。
通常情况下,git clone 远程仓库至本地会创建一个工作目录(例如 A),并在 A 目录下创建 .git 目录以记录 Git 仓库信息。

在 IDE(如 VS Code)中,开发者通常将目录 A 设置为工作区(workspace),以直接访问项目资源,切换分支,提交更改等操作。不过,这种模式只能感知并识别 A 目录下的文件变化,属于 1 仓库:1 工作目录:N 分支 的模式。

而通过 worktree,可以扩展额外的工作目录,使工作模式变为 1 仓库:N 工作目录:N 分支


场景假设

假设如下场景:

张三被开发组长分配了一个新功能开发任务(任务 A),并且组长为他创建了开发分支 dev-a。张三切换到 dev-a 分支后开始开发。正当张三兴致勃勃地推进任务时,项目经理突然冲过来,一边拍桌子一边抱怨:生产环境出了问题,需要立刻修复。开发组长于是创建了 hotfix-b 分支,将这个紧急任务交给张三处理。

由于 hotfix-b 的优先级更高,张三需要暂停任务 A。这时他有三种选择:

  1. 直接提交:将当前 dev-a 的所有内容(包括未完成的开发内容)提交,然后清空工作目录,切换到 hotfix-b 分支,完成修复后切回 dev-a,再通过 soft reset 恢复原有状态。
    缺点:临时提交可能会导致误同步至远程仓库。

  2. 使用 Stash:将当前任务 A 的内容 stash,清空工作目录,切换至 hotfix-b。完成修复后切回 dev-a 分支,并 pop 出之前的 stash 内容继续开发。
    缺点stash 与分支管理不当可能引发冲突。

  3. 使用 Worktree:直接创建一个新的工作目录并关联 hotfix-b 分支。开发完成后,通过 git worktree remove 删除新工作目录,不留任何痕迹。


这是李四举手,说,我觉得方法1,2,3差不太多啊。
李四同学说的对,坐下。

在简单场景下,1,2,3方法差别确实不大,但这里面有个隐含要素。涉及到上下文切换的代价问题。

为什么上下文切换有代价?

在没有电脑的年代,处理多个任务的最佳办法不是将当前办公桌上的资料全部收起来,再重新摆放,而是借用别人的办公桌。上下文切换会中断开发人员的专注,而专注是高效开发的前提。

此外,方法 1 和 2 还引入了额外的管理风险:

  • 方法 1:临时提交可能误同步至远程仓库。
  • 方法 2stash 内容容易误操作或丢失。

相比之下,使用 Worktree 的优势在于:

  • 当前任务的工作目录无需任何改动。
  • 开启新的工作目录对现有任务零侵入。
  • 上下文切换的代价几乎为零。

Worktree 的其他优势

除了多任务切换,worktree 还解决了以下痛点:

  1. 跨分支文件参考
    张三正在开发新功能,但需要查看另一个分支的某个文件状态。使用 worktree,可以直接创建一个新的工作目录以切换到目标分支,而无需清空当前工作内容或放弃现代 IDE 的便利功能。

  2. 代码 Review 场景
    开发组长需要同时完成自己的开发任务和代码审查。如果不使用 worktree,他需要频繁切换分支,这不仅中断开发,还影响效率。而使用 worktree,可以专门创建一个用于 Review 的工作目录,Review 完成后直接关闭即可,丝毫不影响自己的开发喜欢看在线版的随意


我是如何使用 Worktree 的

经过大量实践,我总结出以下常用配置:

  1. Dev 目录:用于完成当前开发任务。
  2. Review 目录:专门用于审查别人的提交。
  3. Main 目录:参考主分支或特定分支的代码。
  4. Release 目录:用于准备当前 Sprint 的发布内容。

可能有人会问:“直接多 clone 一份仓库不也行吗?”
理论上可以,你硬盘大CPU快你有理。但 worktree 的优势在于:

  • 多个目录共享同一组 .git 信息,避免冗余。
  • 节省磁盘空间和文件碎片。
  • 执行效率更高。

有些软件开发公司并没有给开发同学配备高性能的电脑,任何拖累性能的东西都是压死骆驼的最后一根稻草。
此外,共享 .git 的工作目录还能继承本地设置(如 git hookgit config 等),无需重复配置。

git worktree命令简明说明

// 列出当前所有worktree
git worktree list

// 创建基于特定分支的工作目录
git worktree add ../[目录名] [分支名]

// 删除特定的工作目录
git worktree remove ../[目录名]

感谢阅读,最后,愿天下的程序员都能需要一个好经理,不需要疯狂加班。

此文章由AI辅助完成