Jujutsu 大规模合并:为了乐趣与收益

Lobsters Hottest 工具

摘要

本技术指南介绍 Jujutsu(一款替代 Git 的版本控制系统)中的“megamerge”工作流,讲解如何利用章鱼式合并(octopus merges,即具有 3 个及以上父提交的提交)高效管理多个并发分支与开发上下文。

<p><a href="https://lobste.rs/s/etrtmp/jujutsu_megamerges_for_fun_profit">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/04/21 02:58

# Jujutsu megamerge:乐趣与实用并存 来源:https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit *本文面向中级 Jujutsu 用户,以及对 Jujutsu 感到好奇的 Git 用户。* 我是 Jujutsu (https://jj-vcs.github.io/jj/latest) 的重度用户,发现自己越来越依赖 JJ 社区中俗称的“megamerge”工作流来进行日常开发。令人意外的是,除了少数高级用户之外,这个话题鲜少被讨论。因此我想分享一下它的具体做法和便利之处,尤其是当你处于复杂的开发环境,或者经常提交大量小型 PR 时。 *赶时间?直接跳到最后 (https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit#tldr) 查看快速技巧。* ## 合并提交并非你想的那样特殊 如果你只是一名普通的 Git 用户(或是尚未深入了解高级工作流的 Jujutsu 用户),你可能会惊讶地发现:合并提交根本没有什么特殊之处。它不是什么拥有特殊规则的特例,只不过是一个拥有多个父提交的普通提交而已。它甚至不一定是空的\1 `` @ myzpxsys Isaac Corbrey 12 seconds ago 634e82e2 │ (empty) (no description set) ○ mllmtkmv Isaac Corbrey 12 seconds ago git_head() 947a52fd ├─╮ (empty) Merge the things │ ○ vqsqmtlu Isaac Corbrey 12 seconds ago f41c796e │ │ deps: Pin quantum manifold resolver ○ │ tqqymrkn Isaac Corbrey 19 seconds ago 0426baba ├─╯ storage: Align transient cache manifolds ◆ zzzzzzzz root() 00000000 `` 把它们合在一起! 你可能还会更惊讶地发现,合并提交并不限于只有两个父提交。我们非正式地将拥有三个及以上父提交的合并提交称为“章鱼合并”(octopus merges)。你也许会在心里嘀咕:“在什么情况下我会想合并两个以上的分支?”但这其实是一个非常强大的概念。章鱼合并正是整个 megamerge 工作流的核心动力! ## 那么,megamerge 到底是什么? 简单来说,在 megamerge 工作流中,你很少直接基于各个分支的顶端进行工作。相反,你会为你关心的每一个工作分支创建一个章鱼合并提交(以下称为“megamerge”),作为这些分支的子提交。这意味着 bug 修复、功能分支、等待 PR 的分支、你需要代码与之兼容的其他人的分支、本地环境配置分支,甚至那些可能不属于任何分支的私有提交——*所有*你在意的内容都放进 megamerge 里。 重要的是要记住:**你不会推送 megamerge**,只推送它所包含的各个分支。 `` @ mnrxpywt Isaac Corbrey 25 seconds ago f1eb374e │ (empty) (no description set) ○ wuxuwlox Isaac Corbrey 25 seconds ago git_head() c40c2d9c ├─┬─╮ (empty) megamerge │ │ ○ ttnyuntn Isaac Corbrey 57 seconds ago 7d656676 │ │ │ storage: Align transient cache manifolds │ ○ │ ptpvnsnx Isaac Corbrey 25 seconds ago 897d21c7 │ │ │ parser: Deobfuscate fleem tokens │ ○ │ zwpzvxmv Isaac Corbrey 37 seconds ago 14971267 │ │ │ infra: Refactor blob allocator │ ○ │ tqxoxrwq Isaac Corbrey 57 seconds ago 90bf43e4 │ ├─╯ io: Unjam polarity valves ○ │ moslkvzr Isaac Corbrey 50 seconds ago 753ef2e7 │ │ deps: Pin quantum manifold resolver ○ │ qupprxtz Isaac Corbrey 57 seconds ago 5332c1fd ├─╯ ui: Defrobnicate layout heuristics ○ wwtmlyss Isaac Corbrey 57 seconds ago 5804d1fd │ test: Add hyperfrobnication suite ◆ zzzzzzzz root() 00000000 `` 吓人!合并太多了! 听起来很复杂也没关系。毕竟,如果你要回头去处理一个旧 PR 让它通过审查,你就知道切换上下文有多费劲了,还有其他种种麻烦。然而,这能为你带来几个非常有价值的优势: 1. **你始终在基于所有工作的总和进行开发。** 这意味着,只要你的工作副本能编译并正常运行,你就知道这些工作之间都能正常交互。 2. **你几乎不用担心合并冲突。** 由于冲突在 Jujutsu 中是一等公民的概念,你本就不太需要为冲突操心;而既然你始终在把自己的改动合并到一起,就永远不会在代码托管平台上遭遇突如其来的合并冲突。偶尔可能会遇到其他贡献者的改动带来的问题,但据我的经验,这并不算大问题。 3. **切换任务时的摩擦大大减少。** 因为你始终工作在 megamerge 之上,所以不需要去 VCS 里切换任务,直接编辑你需要的内容即可。这也意味着,顺手做一些重构或修 bug 并提交小型 PR 变得更加容易。 4. **保持分支最新变得更加容易。** 借助一点技巧,你可以用一条 rebase 命令就把整个 megamerge 变基到主干分支上。我稍后会演示。 ## 如何创建一个 megamerge? 开始一个 megamerge 非常简单:只需新建一个提交,把你想要包含的每个分支作为它的父提交即可。我喜欢给这个提交起个名字并留空,像这样: `` jj new x y z jj commit --message "megamerge" `` 创建 megamerge。其实也没那么难! 然后你就会在整个结构的顶端留下一个空提交。这就是你干活的地方!megamerge 提交之上的任何东西都被视为 WIP(工作进行中)。你可以根据需要拆分内容,基于 megamerge 提交创建多个分支,想做什么都行。你所写的一切都将基于 megamerge 内所有内容的总和,正如我们所期望的那样! 当然,总有一天你会对现有成果感到满意,然后你就会想: ## 我到底该怎么提交改动? 如何将 WIP 改动纳入 megamerge,取决于它们应该归属到哪里。如果你在做应该归入已有提交的改动,可以使用 `squash` 命令配合 `--to` 标志,把它们放入正确的下游提交中。如果你的提交包含多个提交的改动量,你可以先用 `split` 把它拆成多个提交再压缩,或者(我更喜欢的方式)使用 `squash --interactive` 进行交互式压缩,只挑选出需要移动的具体片段。 `` # 压缩整个 WIP 提交(默认 --from @) jj squash --to x --from y # 交互式压缩 WIP 提交的一部分(默认 --from @) jj squash --to x --from y --interactive `` Hunk,我选择你! 当然,Jujutsu 是一款优雅的软件,为此提供了自动化功能!`absorb` 命令能帮你完成大部分工作:它会识别当前提交的每一行或每一个 hunk 应该属于哪个下游的可变提交,并**自动将它们压缩进去**。每次使用它都感觉像魔法一样(而且不是那种邪恶的黑箱魔法,让你完全无法理解的那种),这是 Jujutsu 的核心功能之一,也是让 megamerge 工作流如此丝滑的关键。 `` # 自动魔法般地压缩你的改动(默认 --from @) jj absorb --from x `` 哎呀,真快。 `absorb` 并不总能抓到你提交里的所有内容,但通常至少能处理 90%。剩下的要么很容易压缩到下游提交,要么与之前的任何提交都无关。 很方便的是,如果我的改动应该属于一个新提交,事情也不会复杂多少。如果这个提交属于我正在处理的某个分支,我可以直接自己变基它,并相应地移动 bookmark。 `` jj commit jj rebase --revision x --after y --before megamerge jj bookmark move --from y --to x `` 我们来拆解一下这个 rebase 命令,以便更好地理解它的工作原理: `` # 我们要移动一些提交! jj rebase # 让我们把 WIP 提交 x... --revision x # 移动到 y(例如 trunk())之后... --after y # 并成为 megamerge 的父提交。 --before megamerge `` 来一点火箭外科手术,当作奖励。 如果我开始了一个全新的功能,或者发现了一个需要修复的不相关的 bug,那就更简单了!借助几个别名,我可以超级轻松地把新改动纳入 megamerge:2 (https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit#user-content-fn-3) 还有模板别名,可以让你使用模板语言 (https://docs.jj-vcs.dev/latest/templates) 更改 Jujutsu 在终端中的日志输出方式;以及文件集别名(fileset aliases),它们与修订集别名类似,但使用文件集语言 (https://docs.jj-vcs.dev

相似文章

jujutsu v0.42.0 发布

Lobsters Hottest

Jujutsu (jj) 版本控制系统发布了 v0.42.0。Jujutsu 是一款开源 VCS,以 Git 作为存储后端,同时提供更符合人体工程学的操作界面,其功能设计灵感来源于 Mercurial、Sapling 和 Darcs。

用Jujutsu战胜Git严谨疲劳

Hacker News Top

本文介绍了一种使用Jujutsu版本控制系统的工作流程,旨在克服在Git中保持严格提交纪律的疲劳感,允许开发者先进行杂乱提交,最后再整洁地重新组织它们。

jj v0.43.0 发布

Lobsters Hottest

Jujutsu v0.43.0,一个与 Git 兼容的版本控制系统,旨在易用性和强大的历史重写功能,现已发布更新。