Jujutsu(jj)同类工具对比指南:从 git-branchless、Sapling 到 GitButler,理解下一代版本控制系统的差异化定位
【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj
Jujutsu(jj)是一个与 Git 兼容、既简单又强大的版本控制系统。本篇指南以官方文档中的 Related work(相关工作) 为核心骨架,逐一剖析jj与 git-branchless、Sapling、GitUp、Gitless、Breezy、GitButler 六款同类工具的关系与差异,并结合仓库内 Sapling 对比文档、Git 对比文档 以及源码实现,帮助你快速建立对版本控制生态的全局认知,并回答一个核心问题:既然已有这么多类似工具,Jujutsu 的设计取舍究竟独特在哪里。
引言:Jujutsu 在版本控制生态中的位置
Jujutsu 的官方文档用一个独立的 Related work 页面列出了六款与它功能相似的现代工具。这些工具共享一个共同的时代背景:传统 Git 的"暂存区 + 分支模型 + 冲突阻塞式工作流"让许多开发者感到繁琐,于是社区从不同角度尝试重新设计版本控制的交互方式——有的通过包装 Git 提供更友好的界面(Gitless、GitButler),有的在 Git 之上叠加撤销与匿名分支能力(git-branchless),有的则是完整重写的独立 VCS(Sapling、Breezy、Jujutsu 本身)。
要理解这份列表,关键是先抓住 Jujutsu 的三个底层设计支柱(它们在 Git 对比文档 中被详细展开):
- 工作副本自动提交:几乎每个
jj命令都会先自动快照工作副本(详见 working-copy.md); - 冲突是一等公民:冲突可以被记录在提交里,而不是阻塞任何操作(详见 conflicts.md);
- 操作日志(operation log)驱动撤销:每次修改仓库的操作都被记录,
jj undo等能力都由它支撑(详见 operation-log.md)。
有了这三根支柱,再去看每一款同类工具,就能立刻看出它们与 Jujutsu 的重合点与分岔点。
git-branchless:在 Git 之上叠加"无分支"工作流
"Helps you use a branchless workflow in your Git repo. Supports anonymous branching, undo, and faster rebase (
git move). Under heavy development and quickly gaining new features."
git-branchless 的思路与 Jujutsu 高度重合:它鼓励用户放弃传统命名分支,改用**匿名分支(anonymous branching)**工作流——即所有提交都叠在一条或多条匿名线上,需要时再打标签。这与 Jujutsu 的"无当前分支"模型几乎同构:Jujutsu 的提交图会跟踪所有可见的匿名头(anonymous heads),提交不会因为"没有分支指向"而丢失或被垃圾回收(参见 glossary.md 中的 Anonymous branch 词条)。
两者都提供undo。但底层机制完全不同:
- git-branchless 构建在 Git 的 reflog 与 refs 之上;
- Jujutsu 拥有独立的操作日志:每个操作对象记录整仓库的 view 快照(所有 bookmark、tag、Git ref 的位置,可见头集合,以及每个工作区的工作副本提交),并指向其父操作形成 DAG。在 cli/src/commands/undo.rs 中,
jj undo的实现(UndoArgs)非常简单,因为"撤销一步"本质上就是从操作日志里选择前一个操作并恢复其 view。
git-branchless 的快速 rebase 功能叫git move;Jujutsu 对应的则是jj rebase,并且由于"自动 rebase 后代提交"机制,jj rebase之后所有后代提交、指向它们的 bookmark 以及工作副本都会自动跟随更新(详见 git-comparison.md)。
关键差异:git-branchless 始终是"Git 之上的一层壳",它无法改变 Git 本身的数据模型;而 Jujutsu 拥有自己的存储层与提交模型(尽管默认后端就是 Git 仓库,见 git-compatibility.md),因此能实现 git-branchless 做不到的能力,例如把冲突本身作为提交内容提交。
Sapling:来自 Meta 的 Mercurial 深度改造分支
"A heavily modified fork of Mercurial developed and used at Meta. It is compatible with Git, has undo functionality, and a graphical interface."
Sapling(sl)是这份列表中最重量级的对手,官方文档专门为它撰写了一篇完整的对比文档:Comparison with Sapling。由于 Jujutsu 从 Mercurial 借鉴了大量思想(revset 语言、堆叠提交、匿名头、split、amend 后自动 rebase 后代等),两者有不少共同点:
- 友好的 CLI;
- 用于选择修订版本的 revset 语言;
- 对堆叠提交的良好支持,包括跟踪匿名头(没有 Git 的 detached HEAD 状态)与
split命令; - 通过 templates 灵活定制输出。
两者之间的具体差异(均来自 sapling-comparison.md):
| 维度 | Jujutsu(jj) | Sapling(sl) |
|---|---|---|
| 工作副本 | 每个命令自动快照,新文件自动跟踪、删除文件自动取消跟踪 | 需要用户显式提交,冲突时命令会失败("abort: 1 conflicting file changes"),需要sl shelve |
| 冲突 | 可以提交冲突(存储的是冲突的逻辑表示,而非<<<<<<<标记),可随时解决、可继续 rebase | 提交前必须解决冲突,自动 rebase 遇到冲突会失败 |
| Undo | 由操作日志驱动,jj op log可直观查看仓库历史并选择回退多远 | 有 MetaLog,但sl debugmetalog看起来只展示单个提交的历史而非整仓库历史 |
| Git 互操作 | 克隆/推送/拉取之外,还支持与 Git 仓库共享同一个工作副本(colocated workspace) | 支持 Git 远端互操作,但不共享工作副本 |
| 打磨程度 | 相对更朴素 | 更完善,自带交互式 Smartlog 网页 UI(可拖拽提交进行 rebase) |
| 代码托管平台(forge)工作流 | 无直接集成;用jj git push --change为指定提交自动建分支 | sl pr submit --stack可将提交栈拆成多个 GitHub PR(仅支持 GitHub) |
其中"工作副本"的差异尤其值得展开。Jujutsu 将工作副本视为一个普通提交(即@),因此在 working-copy.md 中可以看到如下推论:
- 每次运行命令,工作副本都被隐式备份;
- 没有任何命令会因为"工作副本有改动"而失败;
- CLI 更简单一致,因为工作副本与其他提交没有任何区别对待。
这一差异还延伸到 undo:jj undo一次jj commit后,jj diff会显示与提交前完全相同的改动(因为工作副本的改动已被快照进提交,撤销操作能还原它);而sl undo一次sl commit后,工作副本是干净的——改动已经丢进提交里了。
GitUp:Mac 专用的 Git GUI,最早实现"仓库快照式撤销"
"A Mac-only GUI for Git. Like Jujutsu, supports undo and restoring the repo to an earlier snapshot. Backed by its GitUpKit library."
GitUp 的价值在于它证明了"把仓库恢复到任意历史快照"这一交互模式是可行的:它底层由 GitUpKit 库驱动,可以让用户随时回到仓库的早期状态。这正是 Jujutsu 操作日志的核心能力:
jj undo:逐条撤销最近的操作;jj op revert:回退一个并非最新的指定操作;jj op restore:把整个仓库恢复到某个较早操作时的状态。
区别在于,GitUp 是 Mac 平台的 GUI 工具,其撤销能力建立在 Git 的内部结构之上;而 Jujutsu 把"操作历史"做成了仓库数据模型的一等组成部分——操作日志本身就是一个由操作对象构成的 DAG(参考 glossary.md 的 Operation log 词条),并且通过顶层选项--at-operation/--at-op可以把任意命令加载到历史中的某个操作视角上执行(详见 operation-log.md)。
Gitless:简化 Git 界面,但没有暂存区概念的先行者
"Another attempt at providing a simpler interface for Git. Like Jujutsu, does not have an 'index'/'staging area' concept."
Gitless 与 Jujutsu 的核心共鸣点是取消暂存区(index/staging area)。Git 对比文档 git-comparison.md 指出:暂存区本质上就是HEAD与工作副本之间的一个中间提交,因此依赖它的工作流完全可以改用"真正的提交"来建模——Jujutsu 正是这么做的:
- 想要只提交工作副本的一部分改动?Git 习惯用
git add -p; git commit,Jujutsu 用jj split把工作副本提交拆成两个; - 想把改动并回父提交?Git 用
git add -p; git commit --amend,Jujutsu 用jj squash -i选择要移动的改动,或用jj squash <file>移动指定文件。
Gitless 与 Jujutsu 的一个关键分岔点是:Gitless 不会在不同分支之间搬动工作副本的改动,而 Jujutsu 因为把工作副本本身做成一个提交,搬动改动只是 rebase 的自然结果("we do simply as a consequence of making the working copy a commit")。在 Jujutsu 中,从工作副本提交创建新提交、切换基础、合并改动,全部统一为对提交图的改写操作,这是"无暂存区"设计能够成立的根本原因。
Breezy:多存储后端的另一个实践者
"Another VCS that's similar in that it has multiple storage backends, including its own format as well as .git support."
Breezy 与 Jujutsu 的相似点在于多后端存储架构。Jujutsu 的存储层通过 backend 抽象隔离(参见 glossary.md 的 Backend 词条):目前唯一生产可用的内置提交后端是 Git 后端(把提交存进 Git 仓库),另外还有用于测试的多款后端;同时操作日志、工作副本等也各有可插拔的存储后端。Jujutsu 的 Git 后端能力细节可见 git-compatibility.md,包括:
- 用
jj git init --git-repo=<path>基于已有 Git 仓库或裸仓库创建 jj 仓库; - 用
jj git clone <URL>从远端克隆; - colocated workspace 模式下
jj与git命令可在同一工作副本中混用,每次jj命令自动执行 import/export。
相比 Breezy"自带格式 + .git 支持"的路线,Jujutsu 的 Git 兼容性设计得更深入——它可以在不打断 Git 工具链的前提下,与 Git 用户无缝协作。
GitButler:虚拟分支与多分支并行工作的 Git 客户端
"A Git client that works with multiple virtual branches simultaneously, first-class conflicts, and operations history."
GitButler 是一个 Git 客户端(GUI),它提出的**虚拟分支(virtual branches)**概念允许同时并行维护多个逻辑分支,配合一等冲突处理与操作历史。这与 Jujutsu 的工作流殊途同归:Jujutsu 虽然没有 GUI,但在 CLI 层面天然支持多条并行开发线——因为提交图的任何位置都可以长出匿名分支,而 bookmarks(命名指针)只是可选的标签,可以随时移动而不影响其指向提交的身份。
值得注意的差异:GitButler 是构建在 Git 之上的客户端层,而 Jujutsu 是完整的 VCS 实现。Jujutsu 的"一等冲突"意味着冲突可以存在于提交中并被继续 rebase、merge 或 revert(详见 conflicts.md),而不仅仅是在客户端 UI 里被友好地展示。
横向对比:一张表看懂六款工具与 Jujutsu 的关系
| 工具 | 类型 | 与 Jujutsu 的共同点 | 与 Jujutsu 的关键差异 |
|---|---|---|---|
| git-branchless | Git 之上的增强层(CLI) | 匿名分支工作流、undo、快速 rebase | 受限于 Git 数据模型,无法提交冲突 |
| Sapling | 独立 VCS(Mercurial 分支,Meta 开发) | revset、堆叠提交、撤销、Git 兼容 | 需显式提交、冲突阻塞、无 colocated 共享工作副本、有图形界面 |
| GitUp | Mac 专用 Git GUI | 仓库级撤销与快照恢复 | 平台绑定、构建于 GitUpKit 之上 |
| Gitless | Git 之上的简化 CLI | 无暂存区概念 | 不搬动工作副本改动跨分支 |
| Breezy | 独立 VCS | 多存储后端(自有格式 + .git) | 走传统提交模型 |
| GitButler | Git 客户端(GUI) | 多分支并行、一等冲突、操作历史 | 是客户端而非 VCS 本体 |
从源码看 Jujutsu 差异化能力的实现锚点
如果你希望验证上述对比中"Jujutsu 独有能力"的真实性,可以在本仓库中找到对应的实现与测试证据:
- 自动快照工作副本:实现位于 lib/src/local_working_copy.rs,配套文档见 working-copy.md,测试见 lib/tests/test_local_working_copy.rs;
- 一等冲突(commit 可携带冲突):核心逻辑在 lib/src/conflicts.rs 与 lib/src/merged_tree.rs,测试见 lib/tests/test_conflicts.rs;冲突标记的"快照 + 多个 diff"式物化格式详见 conflicts.md;
- 操作日志与 undo:
jj op log、jj undo、jj op restore的命令实现位于 cli/src/commands/operation/ 与 cli/src/commands/undo.rs,操作存储抽象见 lib/src/op_store.rs; - 匿名分支 / 可见头跟踪:view 对象记录所有可见头,相关概念见 glossary.md,view 实现见 lib/src/view.rs;
- Git 后端与 colocated 工作区:见 lib/src/git_backend.rs 与 cli/src/commands/git/,
jj git colocation命令在 cli/src/commands/git/colocation.rs。
结语:Jujutsu 的差异化定位
纵观六款同类工具,"简化 Git"是共同目标,但实现的层次不同:git-branchless、Gitless、GitButler 是在 Git 之上做增强或包装,受制于 Git 的数据模型;Sapling、Breezy 是完整重写的 VCS,但保留了传统"显式提交、冲突阻塞"的交互;GitUp 则是单平台 GUI。
Jujutsu 的独特之处在于:它重新设计了数据模型(提交可携带冲突、操作日志记录一切、工作副本即提交),同时保证与 Git 仓库深度兼容——这使得它既拥有下一代 VCS 的表达能力,又能无缝融入现有 Git 协作生态。判断它是否适合你,可以从这三个问题入手:你是否厌倦了显式git add/git commit与"先解决冲突才能继续"的阻塞式流程?你是否频繁需要撤销/回退仓库状态?你的团队是否愿意在一个"用 jj 命令操作、底层仍是 Git 仓库"的环境里协作?如果答案是肯定的,那么 Jujutsu 值得你花一个下午用 tutorial.md 实际体验一番。
【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考