Jujutsu 社区最近把一套少数高频用户常用的做法写成了教程:先造一个本地的多父 merge commit,把你自己的功能分支、修复分支、待审 PR,甚至别人还没并入主干的依赖分支,一股脑合到一个“总视图”里;之后你始终站在这个总和上开发,再用 absorbsquash --interactiverebase 和几组 alias,把改动拆回各自分支去提交。

这次补充信息比旧稿更关键的地方,在于它不再只是说“版本控制应该更懂上下文”,而是给出了一个具体模型:如果你手里同时挂着三五条 PR,工具能不能别逼你来回 checkout、反复找状态、靠脑补判断几条分支能不能共存?JJ 至少已经把这件事,从高手口耳相传的手活,推进到了可解释、可练习、可复制的层面。

新补了什么:不是新命令,是“本地集成层”

旧稿的主线,是版本控制不该只会逐行对比,也该更理解开发者真实在处理的工作单元。新线索补强的,不是一个零碎技巧,而是一整套操作思路。

megamerge 本质上不神秘。merge commit 只是一个有多个父节点的 commit;两个父节点是普通 merge,三个以上在 Git 语境里常被叫 octopus merge。新东西在于,JJ 用户把它从“偶尔合一下”的动作,变成了一个长期存在的本地集成层。

它解决的是很具体的三件事:

  • 你总能在“所有相关工作之和”上编译、运行、测试。
  • 冲突会更早出现,不容易等到 PR 合并时才被突袭。
  • 你不用为了改一条旧 PR,反复切分支、重捡上下文、再把栈理一遍。

作者也讲得很清楚:这个 megamerge 通常不推远端。推到远端的,还是组成它的那些分支。这个限制很重要。它说明这不是拿远端历史做实验,而是在本地先把认知负担压平。

对长期并行维护多条 PR 的开发者,这个价值非常现实。过去你像在几个平行宇宙之间来回穿梭;现在更像先把宇宙叠起来,看见全局,再决定每一块改动该落到哪里。

为什么 JJ 里顺,Git 里却总让人心虚

这里最容易吹过头。Git 不是做不到。多父 merge、octopus merge、rebase,它全都有。问题不在“有没有这个命令”,而在“主流模型是不是鼓励你这样做”。

Git 的默认心智,是分支便宜,所以多开分支;分支多了,就晚点集成;晚点集成,冲突就后置;冲突后置,认知负担就回到人脑。听起来很熟,因为这是大多数团队每天都在交的税。

JJ 让 megamerge 这套东西更顺,靠的是几个结构性差异。

  • 冲突在 JJ 里是 first-class concept,不是临时事故。
  • 它区分 mutable / immutable commit,哪些能改,哪些别碰,边界更清楚。
  • absorb 很关键.它能按 hunk 把当前改动自动吸收到下游可变提交里,省掉大量手工整理。

新线索还补了 alias 设计的细节,这不是小装饰。stackstagerestack 这些别名,实际是在把“跟主干同步”“把本地总视图之后的一段栈重排”“只重写可变提交”这些动作,压成可重复的工作流。

换句话说,JJ 不只是让你能折腾历史,而是让你在折腾时更知道自己在碰什么。差别就在这儿:Git 里这类操作常给人一种“历史要炸了”的心虚感,JJ 则试图把它变成受控改写。

我更认同的说法是:JJ 不是凭空发明了新能力,它只是把 Git 早就有、但一直很别扭的图操作,改造成了更适合日常并行开发的产品模型。

这对谁最重要:不是所有开发者,是那批“长期挂很多 PR 的人”

受影响最大的人,其实没那么多。

第一类,是中高级开发者,尤其是长期同时维护多条小 PR、经常跨分支顺手修 bug、给别人的分支补依赖的人。你们最清楚,真正拖慢效率的往往不是写代码,而是找上下文、切状态、补脑内依赖图。

第二类,是已经认真评估 JJ 的团队。不是因为它时髦,而是因为它在一个老问题上给了更实操的答案:多任务并行到底能不能不靠自我感动硬扛。

普通只维护单条 feature branch、提完就合的开发者,暂时没必要把这套方法奉为圣经。工具再强,也不值得为了炫技把简单流程复杂化。

我买账这套方法,但不买账围绕它的轻松叙事

新线索也补了一个很重要的限制:这套 megamerge 工作流,目前更像 power user 的实践,不是官方标准流程,也还算不上社区共识。这个判断我很认同,而且必须写在前面,不然读者很容易误会成“JJ 已经把多分支开发彻底解决了”。

没有。它只是把问题处理得更像工程,而不是更像巫术。

你要用好这套方法,至少得满足几件事:理解 revset;知道哪些提交可变;接受本地历史会反复整理;最关键的是,别把本地 megamerge 乱推上远端。团队纪律差一点,这玩意就不是效率工具,而是事故放大器。

这也是我对 Git 世界最不客气的一点。很多团队嘴上把分支治理讲得像工艺,实际只是把集成成本不断往后扔,最后扔给审查、扔给 CI、扔给合并当天值班的人。天下熙熙,皆为利来;在工程管理里也差不多,谁能把麻烦晚点结算,谁就先显得流程优雅。问题是,账不会消失,只会换个更贵的时候来收。

megamerge 真正戳破的,就是这层遮羞布:

  • 多分支不等于专业。
  • 历史整洁不等于协作高效。
  • 推迟集成,常常不是稳健,而是偷懒。

Linus 当年造 Git,是为了解决代码流转,不是为了让工程师终日搬运上下文。今天不少 Git 团队把分支神圣化,把 checkout 和 rebase 当苦修,把被工具折磨误当成工程 discipline。我不太买账。那不是严谨,更多是旧工具心智被制度化之后的惯性。

历史上每次基础工具升级,都会出现同一种戏码:旧世界先把额外摩擦说成必要复杂性,等新工具把摩擦抹平,又有人出来把旧痛苦包装成“专业门槛”。这事很像早年的集中式版本控制转向分布式时的争论,不完全一样,但味道很像:守旧者总把低效解释为秩序,把体力活解释为控制感。

JJ 眼下最值得观察的,不是 megamerge 会不会火出圈,而是它能不能把这套做法继续沉淀成更可教、更可审计、更不容易误用的团队实践。要是始终只停留在高手 alias 和个人手感,那它再强,也还只是偏方,不是方法。

我最后还是回到旧稿那条主线:版本控制该更懂业务。现在的新证据是,JJ 至少在“多条相关工作如何一起活”这件事上,已经比 Git 主流工作流更像在服务开发者,而不是要求开发者迁就它。

分久必合。过去合的是代码仓库;现在更该合的,是工程师被切碎的工作视图。