Git Worktree:AI 时代,构建个人开发者的 Monorepo 线性工作流

本文将介绍如何利用 Worktree 建立多个并行工位,并通过“变基、气泡合并、归位重置”三部曲,让你的 Git 历史不仅美观且易于回溯。如果你也是追求效率与 Git 历史审美的个人开发者,这套工作流绝对值得一试。

Git Worktree:AI 时代,构建个人开发者的 Monorepo 线性工作流

Monorepo 在 AI 时代非常好用:

在一个 git 仓库里面,把整个项目包括前端和后端都放在一起,AI 可以直接获得整个项目的上下文信息,对于共享的数据模型和 API 契约理解更深刻,改起来更准确。

而且 Monorepo 的版本管理很方便:前后端可以同步修改,一个提交就能包含完整的功能链条,不存在多仓库并行开发的版本冲突。

但是这也带来了一个问题:我希望我的一个 Git 历史比较纯净,不要有混杂了前端和后端的提交,因此我还是没办法同时修改前后端。

Or is it?

Monorepo + Git Worktree

Git Worktree,让 AI 牛马加倍干活

实现多个窗口同时干活,最简单的就是再 clone 一个文件夹,但是这样很浪费空间(实际上是同时维护了两个相同的 git 历史),而且同步起来也很麻烦,需要不断地 pull 和 push。还好 git 提供了 worktree,可以完美解决这个问题。

Worktree 本质上是使用了同一个 .git 来管理仓库,但是把代码文件复制了一份到另一个目录。本质上相当于同一个仓库,在不同的目录同时检出了不同的分支。这样一来,就可以同时在两个分支上干活了。

也正因为本质是同一个仓库,所以在一个目录中操作了之后(比如 merge 到了 main),另一个目录可以马上感知,这样就方便了不同分支之间的同步。

使用 worktree 也很简单:

# 创建一个和当前目录同级的 worktree, 目录名为 frontend, 分支名为 frontend-dev
git worktree add ../frontend frontend-dev

# 查看所有的 worktree
git worktree list

# 删除某个 worktree
git worktree remove ../frontend

接下来就可以在两个目录同时工作了!

代码同步

之前在同一个分支里面,还能偷懒直接在 main 分支里面从头干到尾,但是在不同分支却没办法这样干了。不过相比行业内常见的每个功能都是一个分支,我也可以一个分支从头干到尾,这样我就不用每个分支都要取名字,也不需要在任务结束之后手动删除分支,解放大脑!

由于不同的 worktree 里面的代码大概率是不相交的(否则也没必要使用不同的分支来干活),所以合并的时候很少会有冲突。因此我的工作流是:

  1. Work:在某一个分支(例如 dev 分支)内持续工作,提交了一些 commit 之后,该同步到 main 分支了
  2. Rebase:由于想要保证线性历史,此时首先同步 main 的修改:git rebase main (大概率是没有任何冲突的,如果有的话一般都要 Accept Current Change)
  3. Merge:然后切换到 main 分支,使用 git merge --no-ff 。这样做,相比默认的 Fast-forward,可以保留“这个修改来自另一个分支”的信息, git 历史看起来像是新增了一个气泡,整个气泡是一个整体的功能性更新,气泡内部的 commit 是细粒度的修改。
Bubble merge
  1. Reset:然后,返回 dev 分支,git reset --hard main ,让开发分支对齐主干,迎接下一个功能循环。

搭配多个分支,最后 git 历史会变成这样,十分美观:

Git history

再来一个我眼中不美观的例子(不同分支交织在一起):

Ugly git history

自动化

为了方便,我写了一个自动化脚本,可以较为稳健地完成上述功能,感兴趣的可以来试试:

专为个人开发者 Monorepo/Worktree 打造的 Git 智能同步脚本:支持固定开发分支的循环复用,构建整洁的线性“气泡”历史。
专为个人开发者 Monorepo/Worktree 打造的 Git 智能同步脚本:支持固定开发分支的循环复用,构建整洁的线性“气泡”历史。 - git-sync.sh