jj:用 29000 颗星告诉你,Git 该被重新设计了

jj:用 29000 颗星告诉你,Git 该被重新设计了

Seven

你有没有在 git rebase 冲突后手足无措过?有没有误操作后翻遍 git reflog 找回丢失的提交?有没有觉得 git addgit commit 这套暂存区流程多余?

如果这些问题你都遇到过,那你应该认识一下 jj——一个用 Rust 编写、兼容 Git、却从根本上重新设计了版本控制模型的工具。它的 GitHub 仓库在 2026 年 6 月已经突破 29000 颗星,最新版本 v0.41.0 刚在 5 月发布,背后站着 Google 工程师 Martin von Zweigbergk。

jj vs Git 工作流对比

一、jj 是什么

jj(Jujutsu 的缩写)是一个版本控制系统,但它不是要取代 Git——它坐在 Git 之上,用 Git 仓库作为底层存储,同时提供一套完全不同的用户接口。

简单说:你用 jj 操作,数据存在 Git 仓库里,GitHub、GitLab 照常能用。

这意味着什么?你不需要说服整个团队一起迁移。你可以一个人用 jj,队友继续用 Git,你们推拉代码互不影响。

jj 核心架构

二、工作副本 = 提交:告别暂存区

Git 有三层:工作区 → 暂存区(index)→ 仓库。每次修改文件后,你需要 git add 把变更放进暂存区,再 git commit 提交。

jj 砍掉了中间那层。你编辑文件,jj 自动在后台创建快照(snapshot),每次操作都会把当前工作区状态记录为一个提交。这意味着:

  • 没有 git add——编辑即记录
  • 没有 git stash——切换分支时工作区变更自动跟随
  • 没有 detached HEAD——你永远在一个变更(change)上工作

这对新手来说是巨大的认知减负。你不需要理解「暂存区到底是什么」,只需要知道「编辑 → 描述 → 推送」。

三、操作日志:版本控制的时间机器

这是 jj 最让人安心的功能。

每一次操作——新建提交、变基、推送、合并——都被记录在操作日志里。你可以用 jj op log 查看完整历史,用 jj undo 撤销上一步操作,用 jj op revert @-- 回到任意历史状态。

操作日志示意

git reflog 相比,jj 的操作日志是结构化的:每一步都有明确的操作类型、影响的提交、时间戳。你不需要猜 SHA,不需要在一堆哈希值里大海捞针。

一个真实场景:你误删了一个提交(jj abandon),过了两分钟才意识到。在 Git 里你需要翻 reflog 找到那个 SHA,然后 cherry-pick 回来。在 jj 里,jj undo 一条命令搞定。

四、Revset:用 SQL 的方式查询提交

jj 有一套查询语言叫 Revset,用来选择提交。它的表达能力远超 Git 的 --grep--author

几个例子:

  • jj log -r 'all()'——查看所有提交
  • jj log -r 'author(张三) & date(after:2026-05-01)'——张三在 5 月后的提交
  • jj log -r 'children(abc123)'——某个提交的所有子提交
  • jj log -r 'heads(all())'——所有分支的头部提交

Revset 还支持集合运算(交集、并集、差集),可以用 :: 表示祖先/后代关系。这在处理复杂的分支历史时特别有用。

五、冲突是一等公民

Git 处理冲突的方式是「阻塞」:遇到冲突,rebase 暂停,你必须立刻解决,然后 git rebase --continue

jj 不一样。冲突被记录为提交的一部分,你可以继续工作,稍后再解决。如果冲突在提交 A 里被解决,这个解决方案会自动传播到 A 的所有后代提交。

这像什么?像 Git 的 rerere(reuse recorded resolution),但是内建在设计里,不需要额外配置。

六、自动变基:改一个提交,后代自动跟上

在 jj 里,当你修改一个提交(比如 jj squash 合并变更、jj rebase 移动位置),所有后代提交会自动变基到新位置。

举个例子:你有三个提交 A → B → C。你用 jj rebase -r A -d main 把 A 移到 main 最新。Git 需要你手动 rebase B 和 C,或者用 --update-refs。jj 直接帮你做了,B 和 C 自动跟上。

七、与 Git 的兼容性

jj 使用 Git 仓库作为后端存储,这意味着:

  • 你可以在任何现有的 Git 仓库上使用 jj git init --git-repo .
  • jj git pushjj git fetch 直接操作 Git 远程
  • GitHub PR、GitLab MR 都能正常使用
  • 你的 .gitignore 会被尊重

但有一些差异需要注意:

  • jj 用 Change ID(而非 Git commit SHA)跟踪提交的「身份」
  • 书签(bookmark)对应 Git 的分支,但语义不同
  • 某些 Git 操作(如 git cherry-pick)需要用 jj 的原生命令替代

八、安装和上手

安装很简单。macOS 用 Homebrew:

1
brew install jj

Linux 用 cargo(需要 Rust 工具链):

1
cargo install --git https://github.com/jj-vcs/jj jj-cli

Windows 直接去 GitHub Releases 下载预编译包。

在现有 Git 仓库上初始化:

1
2
cd your-git-repo
jj git init --git-repo .

然后就可以用 jj 命令操作了。所有变更通过 jj git push 推到远程 Git 仓库。

九、局限性

jj 不是银弹。几个现实问题:

学习成本:虽然 jj 比 Git 简单,但你的肌肉记忆是 Git 的。git add 变成不需要了,git checkout 变成 jj new,这些转换需要时间。

生态不成熟:VS Code 的 jj 插件还在开发中,CI/CD 集成不如 Git 丰富,教程和社区资源远少于 Git。

大仓库性能:在超大型仓库(monorepo)上,jj 的某些操作比 Git 慢。Google 内部有自己的后端(Piper/CitC),但开源版用的还是 Git 后端。

团队采纳摩擦:你一个人用 jj 没问题,但如果想让团队一起用,说服成本不低。

分支管理语义差异:jj 的「书签」(bookmark)和 Git 的「分支」(branch)概念不同,切换时需要适应。

十、为什么值得关注

jj 的价值不在于「替代 Git」,而在于它证明了版本控制的模型可以被重新设计。29000 颗星说明开发者社区对现状不满,对更好的工具有真实需求。

如果你是个人开发者,或者团队里只有你一个人想尝试新工具,jj 值得花一个下午体验一下。它不会改变你的 Git 仓库,但可能会改变你对版本控制的理解。

相关链接

  • 标题: jj:用 29000 颗星告诉你,Git 该被重新设计了
  • 作者: Seven
  • 创建于 : 2026-06-04 16:00:00
  • 更新于 : 2026-06-04 10:08:26
  • 链接: https://blog.oneiseven.top/2026/06/04/jj-jujutsu-重新定义版本控制/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论