theo-jujutsu

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Theo Ai's Jujutsu (jj) Version Control Guide

Theo Ai 的 Jujutsu (jj) 版本控制指南

Jujutsu is a modern, Git-compatible version control system that provides a simpler mental model and powerful history editing capabilities. This guide covers jj usage in colocated mode (jj + git sharing the same repository).
Jujutsu 是一款现代化、兼容Git的版本控制系统,它提供了更简洁的心智模型和强大的历史编辑能力。本指南介绍了在共存模式(jj + git 共享同一仓库)下的jj使用方法。

When to Use

使用场景

Use this skill when working with version control in a jj repository:
  • Creating, describing, or editing commits
  • Viewing repository status, history, or diffs
  • Rebasing, squashing, or splitting commits
  • Managing bookmarks (jj's equivalent of branches)
  • Pushing to or fetching from Git remotes
  • Resolving conflicts
  • Recovering from mistakes with operation history
  • Any task involving
    jj
    commands
当你在jj仓库中进行版本控制操作时,可以使用本技能:
  • 创建、描述或编辑提交
  • 查看仓库状态、历史记录或差异
  • 变基、合并或拆分提交
  • 管理书签(jj中对应Git分支的概念)
  • 向Git远程仓库推送或拉取代码
  • 解决冲突
  • 通过操作历史恢复错误操作
  • 任何涉及
    jj
    命令的任务

Core Concepts

核心概念

Key Differences from Git

与Git的关键差异

ConceptGitJujutsu
Staging areaExplicit
git add
required
None - working copy IS a commit
Working copyDetached from commitsAlways a commit (
@
)
BranchesNamed refs that must be managedBookmarks (optional, auto-follow rewrites)
StashSeparate stash stackNot needed - just create new commits
Amending
git commit --amend
Just edit files - changes auto-apply to
@
ConflictsBlock operations until resolvedTracked as values, don't block operations
History editingRequires careful rebasingDescendants auto-rebase when you modify history
概念GitJujutsu
暂存区需要显式执行
git add
无暂存区——工作副本本身就是一个提交
工作副本与提交分离始终是一个提交(
@
分支需要管理的命名引用书签(可选,自动跟随重写)
暂存栈独立的暂存栈无需使用——只需创建新提交
修改提交
git commit --amend
直接编辑文件——变更会自动应用到
@
冲突阻塞操作直到解决作为值跟踪,不会阻塞操作
历史编辑需要谨慎变基修改历史时,后代提交会自动变基

The Working Copy Model

工作副本模型

In jj, your working copy (
@
) is always a commit. Every file change is automatically part of this commit - no staging required.
parent commit (@-)
      |
      v
  @ (working copy) <-- your edits apply here automatically
When you run
jj new
, you create a new empty commit on top of
@
, and that becomes your new working copy.
在jj中,你的工作副本(
@
)始终是一个提交。所有文件变更都会自动成为该提交的一部分——无需暂存。
父提交 (@-)
      |
      v
  @ (工作副本) <-- 你的编辑会自动应用到此处
当你运行
jj new
时,会在
@
之上创建一个新的空提交,它将成为你的新工作副本。

Identity: Change ID vs Commit ID

标识:变更ID vs 提交ID

Every commit in jj has two identifiers:
  • Change ID: Stable across rewrites (e.g.,
    kpqxywon
    )
  • Commit ID: Changes when commit content changes (like git SHA)
Use Change IDs when referring to commits - they survive rebases and amendments.
jj中的每个提交都有两个标识符:
  • 变更ID:在重写过程中保持稳定(例如:
    kpqxywon
  • 提交ID:当提交内容变更时会改变(类似Git的SHA值)
引用提交时请使用变更ID——它们在变基和修改提交后仍然有效。

Terminology Mapping

术语映射

Git Termjj TermNotes
branchbookmarkBookmarks auto-follow when commits are rewritten
HEAD
@
The working copy commit
HEAD~1
@-
Parent of working copy
checkout
edit
or
new
edit
moves @,
new
creates child commit
staging/index(none)Not applicable - all changes are tracked
stash(none)Just create a new commit instead
remote branch
name@origin
e.g.,
main@origin
Git 术语jj 术语说明
branchbookmark书签会在提交被重写时自动跟随
HEAD
@
工作副本提交
HEAD~1
@-
工作副本的父提交
checkout
edit
new
edit
移动@,
new
创建子提交
staging/index不适用——所有变更都会被跟踪
stash只需创建新提交即可
remote branch
name@origin
例如:
main@origin

Git-to-jj Command Translation

Git到jj的命令对照表

Everyday Commands

日常命令

GitjjNotes
git status
jj st
Shows working copy status
git diff
jj diff
Diff of working copy
git diff --staged
(none)No staging area
git log --graph
jj log
Shows commit graph
git show <commit>
jj show <rev>
Show commit details
git add . && git commit -m "msg"
jj commit -m "msg"
Commit and create new working copy
git commit --amend
(just edit files)Working copy auto-amends
git commit --amend -m "msg"
jj describe -m "msg"
Change commit message
Gitjj说明
git status
jj st
显示工作副本状态
git diff
jj diff
显示工作副本的变更
git diff --staged
无暂存区
git log --graph
jj log
显示提交图
git show <commit>
jj show <rev>
显示提交详情
git add . && git commit -m "msg"
jj commit -m "msg"
提交变更并创建新工作副本
git commit --amend
直接编辑文件即可工作副本会自动更新
git commit --amend -m "msg"
jj describe -m "msg"
修改提交信息

Branching & Navigation

分支与导航

GitjjNotes
git branch
jj bookmark list
List bookmarks
git branch <name>
jj bookmark create <name>
Create bookmark at @
git checkout <branch>
jj edit <rev>
Move @ to revision
git checkout -b <name>
jj new && jj bookmark create <name>
New commit + bookmark
git switch -
jj edit @-
Go to parent
git stash
jj new
Start new commit (old work stays)
git stash pop
jj edit <prev>
Go back to previous commit
Gitjj说明
git branch
jj bookmark list
列出所有书签
git branch <name>
jj bookmark create <name>
在当前提交创建书签
git checkout <branch>
jj edit <rev>
将@移动到指定版本
git checkout -b <name>
jj new && jj bookmark create <name>
创建新提交并添加书签
git switch -
jj edit @-
回到父提交
git stash
jj new
创建新提交(旧工作内容保留)
git stash pop
jj edit <prev>
回到之前的提交

History Editing

历史编辑

GitjjNotes
git rebase -i
jj squash
,
jj split
,
jj edit
Various commands
git rebase <onto>
jj rebase -d <dest>
Rebase current commit
git cherry-pick <commit>
jj new <dest> && jj restore --from <source>
Copy changes
git reset --hard
jj restore
Discard working copy changes
git reset --soft HEAD~1
jj squash
Fold into parent
git revert <commit>
jj backout -r <rev>
Create inverse commit
Gitjj说明
git rebase -i
jj squash
,
jj split
,
jj edit
多种命令组合使用
git rebase <onto>
jj rebase -d <dest>
变基当前提交
git cherry-pick <commit>
jj new <dest> && jj restore --from <source>
复制变更
git reset --hard
jj restore
丢弃工作副本的变更
git reset --soft HEAD~1
jj squash
合并到父提交
git revert <commit>
jj backout -r <rev>
创建反向提交

Remote Operations

远程操作

GitjjNotes
git fetch
jj git fetch
Fetch from remotes
git pull
jj git fetch && jj rebase -d main@origin
Fetch + rebase
git push
jj git push -b <bookmark>
Push specific bookmark
git push -u origin <branch>
jj git push --bookmark <name>
Push and track
Gitjj说明
git fetch
jj git fetch
从远程仓库拉取
git pull
jj git fetch && jj rebase -d main@origin
拉取并变基
git push
jj git push -b <bookmark>
推送指定书签
git push -u origin <branch>
jj git push --bookmark <name>
推送并跟踪

Other Commands

其他命令

GitjjNotes
git blame <file>
jj file annotate <file>
Show line-by-line authorship
git clean -fd
jj restore
Remove untracked changes
git reflog
jj op log
Operation history
Gitjj说明
git blame <file>
jj file annotate <file>
显示每行代码的作者信息
git clean -fd
jj restore
移除未跟踪的变更
git reflog
jj op log
操作历史

Essential Commands

核心命令

Viewing State

查看状态

bash
undefined
bash
undefined

Show working copy status

显示工作副本状态

jj status jj st # short form
jj status jj st # 简写形式

Show commit log (graph view)

显示提交日志(图形化视图)

jj log jj log -r 'all()' # show all commits jj log -n 20 # limit to 20 commits jj log -r 'bookmarks()' # commits with bookmarks
jj log jj log -r 'all()' # 显示所有提交 jj log -n 20 # 限制显示20个提交 jj log -r 'bookmarks()' # 显示带有书签的提交

Show diff

显示变更

jj diff # working copy changes jj diff --git # git-compatible format jj diff -r <rev> # diff of specific commit jj diff --from <rev1> --to <rev2> # diff between revisions
jj diff # 工作副本的变更 jj diff --git # Git兼容格式 jj diff -r <rev> # 显示指定提交的变更 jj diff --from <rev1> --to <rev2> # 显示两个版本之间的变更

Show commit details

显示提交详情

jj show # current commit jj show <rev> # specific commit
undefined
jj show # 当前提交 jj show <rev> # 指定提交
undefined

Creating and Describing Commits

创建与描述提交

bash
undefined
bash
undefined

Describe current working copy (set/update message)

描述当前工作副本(设置/更新提交信息)

jj describe -m "feat: add user authentication" jj desc -m "fix: resolve login issue" # short form
jj describe -m "feat: 添加用户认证" jj desc -m "fix: 修复登录问题" # 简写形式

Create new empty commit on top of current

在当前提交之上创建新的空提交

jj new jj new -m "feat: starting new feature" # with message
jj new jj new -m "feat: 开始开发新功能" # 附带提交信息

Create new commit on specific parent(s)

在指定父提交之上创建新提交

jj new <rev> # single parent jj new main # based on main jj new <rev1> <rev2> # merge commit (multiple parents)
jj new <rev> # 单个父提交 jj new main # 基于main分支 jj new <rev1> <rev2> # 合并提交(多个父提交)

Commit current changes and start new working copy

提交当前变更并创建新工作副本

jj commit -m "feat: complete implementation"
jj commit -m "feat: 完成功能实现"

(equivalent to: jj describe -m "msg" && jj new)

(等价于:jj describe -m "msg" && jj new)

undefined
undefined

Navigating History

历史导航

bash
undefined
bash
undefined

Edit (move working copy to) a specific commit

编辑(将工作副本移动到)指定提交

jj edit <rev> jj edit @- # edit parent jj edit main # edit main bookmark
jj edit <rev> jj edit @- # 编辑父提交 jj edit main # 编辑main书签

Navigate relatively

相对导航

jj next # move to child commit jj next --edit # move and edit jj prev # move to parent commit jj prev --edit # move and edit parent
undefined
jj next # 移动到子提交 jj next --edit # 移动并编辑 jj prev # 移动到父提交 jj prev --edit # 移动并编辑父提交
undefined

Editing History

编辑历史

Squash: Combine Commits

合并提交:Squash

bash
undefined
bash
undefined

Squash current commit into its parent

将当前提交合并到其父提交

jj squash jj squash -m "combined message"
jj squash jj squash -m "合并后的提交信息"

Squash specific commit into its parent

将指定提交合并到其父提交

jj squash -r <rev>
jj squash -r <rev>

Squash into a specific destination (not just parent)

将提交合并到指定目标(不限于父提交)

jj squash --into <dest>
jj squash --into <dest>

Interactively select which changes to squash

交互式选择要合并的变更

jj squash -i
undefined
jj squash -i
undefined

Split: Divide a Commit

拆分提交:Split

bash
undefined
bash
undefined

Interactively split current commit into multiple

交互式拆分当前提交为多个提交

jj split
jj split

Split specific commit

拆分指定提交

jj split -r <rev>
jj split -r <rev>

Split by file paths

按文件路径拆分

jj split <file1> <file2> # first commit gets these files
undefined
jj split <file1> <file2> # 第一个提交包含这些文件
undefined

Edit: Modify Historical Commits

编辑历史提交

bash
undefined
bash
undefined

Move working copy to an old commit to edit it

将工作副本移动到旧提交进行编辑

jj edit <rev>
jj edit <rev>

Make your changes (they apply directly to that commit)

进行变更(它们会直接应用到该提交)

All descendant commits automatically rebase

所有后代提交会自动变基

Return to the tip when done

完成后回到最新提交

jj new <tip-rev>
jj new <tip-rev>

or

jj edit <original-working-copy>
undefined
jj edit <original-working-copy>
undefined

Rebase: Move Commits

变基:Rebase

bash
undefined
bash
undefined

Rebase current commit to new destination

将当前提交变基到新目标

jj rebase -d <destination> jj rebase -d main@origin # rebase onto latest main
jj rebase -d <destination> jj rebase -d main@origin # 变基到最新的远程main分支

Rebase specific revision

变基指定版本

jj rebase -r <rev> -d <dest>
jj rebase -r <rev> -d <dest>

Rebase revision and all descendants

变基指定版本及其所有后代

jj rebase -s <source> -d <dest>
jj rebase -s <source> -d <dest>

Rebase entire branch (all ancestors up to destination)

变基整个分支(直到目标的所有祖先)

jj rebase -b <rev> -d <dest>
undefined
jj rebase -b <rev> -d <dest>
undefined

Other History Operations

其他历史操作

bash
undefined
bash
undefined

Abandon (delete) a commit

放弃(删除)提交

jj abandon # current commit jj abandon <rev> # specific commit
jj abandon # 当前提交 jj abandon <rev> # 指定提交

Duplicate a commit

复制提交

jj duplicate <rev>
jj duplicate <rev>

Create a commit that reverses changes

创建一个反转变更的提交

jj backout -r <rev>
jj backout -r <rev>

Restore files from another revision

从其他版本恢复文件

jj restore --from <rev> # restore all files jj restore --from <rev> <path> # restore specific path
undefined
jj restore --from <rev> # 恢复所有文件 jj restore --from <rev> <path> # 恢复指定路径
undefined

Working with Bookmarks

使用书签

Bookmarks are jj's equivalent of git branches. They're pointers to commits that automatically follow when commits are rewritten.
bash
undefined
书签是jj中对应Git分支的概念。它们是指向提交的指针,在提交被重写时会自动跟随。
bash
undefined

List all bookmarks

列出所有书签

jj bookmark list jj bookmark list --all # include remote bookmarks
jj bookmark list jj bookmark list --all # 包含远程书签

Create bookmark at current commit

在当前提交创建书签

jj bookmark create <name> jj bookmark create feature-x
jj bookmark create <name> jj bookmark create feature-x

Create bookmark at specific revision

在指定版本创建书签

jj bookmark create <name> -r <rev>
jj bookmark create <name> -r <rev>

Move bookmark to current commit

将书签移动到当前提交

jj bookmark set <name> jj bookmark set <name> -r <rev>
jj bookmark set <name> jj bookmark set <name> -r <rev>

Delete bookmark

删除书签

jj bookmark delete <name>
jj bookmark delete <name>

Rename bookmark

重命名书签

jj bookmark rename <old> <new>
jj bookmark rename <old> <new>

Track remote bookmark (for pulling updates)

跟踪远程书签(用于拉取更新)

jj bookmark track <name>@<remote> jj bookmark track main@origin
jj bookmark track <name>@<remote> jj bookmark track main@origin

Untrack remote bookmark

取消跟踪远程书签

jj bookmark untrack <name>@<remote>
undefined
jj bookmark untrack <name>@<remote>
undefined

Git Interop (Colocated Mode)

Git互操作(共存模式)

In colocated mode, jj and git share the same
.git
directory. This is the recommended setup for existing git repositories.
在共存模式下,jj和Git共享同一个
.git
目录。这是现有Git仓库的推荐设置。

Setup

设置

bash
undefined
bash
undefined

Initialize jj in existing git repo

在现有Git仓库中初始化jj

jj git init --colocate
jj git init --colocate

Or clone with colocate

或通过克隆方式启用共存

jj git clone --colocate <url>
undefined
jj git clone --colocate <url>
undefined

Fetching and Pushing

拉取与推送

bash
undefined
bash
undefined

Fetch from all remotes

从所有远程仓库拉取

jj git fetch
jj git fetch

Fetch from specific remote

从指定远程仓库拉取

jj git fetch --remote origin
jj git fetch --remote origin

Push bookmark to remote

推送书签到远程仓库

jj git push --bookmark <name> jj git push -b <name> # short form
jj git push --bookmark <name> jj git push -b <name> # 简写形式

Push all bookmarks

推送所有书签

jj git push --all
jj git push --all

Push and create bookmark in one step

一步创建书签并推送

jj bookmark create my-feature && jj git push -b my-feature
undefined
jj bookmark create my-feature && jj git push -b my-feature
undefined

Remote Bookmark References

远程书签引用

bash
undefined
bash
undefined

Reference remote bookmarks in commands

在命令中引用远程书签

jj log -r main@origin # show remote main jj new main@origin # new commit based on remote main jj rebase -d main@origin # rebase onto remote main
undefined
jj log -r main@origin # 显示远程main分支的提交 jj new main@origin # 基于远程main分支创建新提交 jj rebase -d main@origin # 变基到远程main分支
undefined

Importing Git State

导入Git状态

bash
undefined
bash
undefined

Import refs from git (usually automatic)

从Git导入引用(通常自动完成)

jj git import
jj git import

Export jj state to git

将jj状态导出到Git

jj git export
undefined
jj git export
undefined

Common Workflows

常见工作流

Starting New Work

开始新工作

bash
undefined
bash
undefined

Fetch latest and start from main

拉取最新代码并从main分支开始

jj git fetch jj new main@origin -m "feat: add user dashboard"
jj git fetch jj new main@origin -m "feat: 添加用户仪表盘"

Create a bookmark for the feature

为功能创建书签

jj bookmark create feat/user-dashboard
undefined
jj bookmark create feat/user-dashboard
undefined

Daily Development Flow

日常开发流程

bash
undefined
bash
undefined

Check status

检查状态

jj st
jj st

Make changes (automatically tracked)

进行变更(自动跟踪)

Edit files...

编辑文件...

Update commit message when ready

准备好后更新提交信息

jj describe -m "feat: implement dashboard layout"
jj describe -m "feat: 实现仪表盘布局"

View what you've done

查看完成的工作

jj diff jj log
jj diff jj log

Start next piece of work

开始下一部分工作

jj new -m "feat: add dashboard widgets"
undefined
jj new -m "feat: 添加仪表盘组件"
undefined

PR Workflow

PR工作流

bash
undefined
bash
undefined

1. Start feature from main

1. 从main分支开始功能开发

jj git fetch jj new main@origin -m "feat: new feature" jj bookmark create feat/my-feature
jj git fetch jj new main@origin -m "feat: 新功能" jj bookmark create feat/my-feature

2. Work on feature (changes auto-tracked)

2. 开发功能(变更自动跟踪)

... make changes ...

... 进行变更 ...

jj describe -m "feat: complete implementation"
jj describe -m "feat: 完成功能实现"

3. Before pushing, rebase onto latest main

3. 推送前,变基到最新的main分支

jj git fetch jj rebase -d main@origin
jj git fetch jj rebase -d main@origin

4. Push to remote

4. 推送到远程仓库

jj git push -b feat/my-feature
jj git push -b feat/my-feature

5. Create PR via GitHub/GitLab UI or CLI

5. 通过GitHub/GitLab UI或CLI创建PR

undefined
undefined

Updating PR After Review

评审后更新PR

bash
undefined
bash
undefined

Fetch to see if main has moved

拉取代码查看main分支是否有更新

jj git fetch
jj git fetch

If you need to edit a specific commit in your stack:

如果需要修改提交栈中的某个特定提交:

jj edit <commit-to-fix>
jj edit <需要修复的提交>

Make changes...

进行变更...

Descendants auto-rebase

后代提交会自动变基

Return to working on tip

返回最新提交继续工作

jj new <tip-of-your-branch>
jj new <你的分支的最新提交>

Or if adding changes to current commit, just edit files

或者如果要向当前提交添加变更,直接编辑文件即可

Rebase onto latest main

变基到最新的main分支

jj rebase -d main@origin
jj git fetch jj rebase -d main@origin

Force push (bookmark moved)

强制推送(书签已移动)

jj git push -b feat/my-feature
undefined
jj git push -b feat/my-feature
undefined

Cleaning Up Before Merge

合并前清理

bash
undefined
bash
undefined

Squash fixup commits

合并修复提交

jj squash -r <fixup-commit>
jj squash -r <fixup-commit>

Or interactively squash

或交互式合并

jj squash -i
jj squash -i

Ensure rebased on latest main

确保已变基到最新的main分支

jj git fetch jj rebase -d main@origin
jj git fetch jj rebase -d main@origin

Final push

最终推送

jj git push -b feat/my-feature
undefined
jj git push -b feat/my-feature
undefined

Working on Multiple Things

同时处理多项工作

bash
undefined
bash
undefined

You're working on feature A

正在开发功能A

jj describe -m "feat: feature A in progress"
jj describe -m "feat: 功能A开发中"

Need to quickly work on something else

需要快速处理其他任务

jj new main@origin -m "fix: urgent hotfix" jj bookmark create fix/urgent
jj new main@origin -m "fix: 紧急修复" jj bookmark create fix/urgent

Work on hotfix...

处理紧急修复...

jj describe -m "fix: resolve critical bug" jj git push -b fix/urgent
jj describe -m "fix: 解决严重bug" jj git push -b fix/urgent

Return to feature A

返回功能A继续开发

jj edit <feature-a-commit>
jj edit <功能A的提交>

or

jj new <feature-a-commit>
undefined
jj new <功能A的提交>
undefined

Conflict Resolution

冲突解决

How jj Handles Conflicts

jj如何处理冲突

Unlike git, jj doesn't block operations when conflicts occur. Conflicts are stored as part of the commit and can be resolved later.
bash
undefined
与Git不同,jj在发生冲突时不会阻塞操作。冲突会作为提交的一部分被存储,可以稍后解决。
bash
undefined

Check for conflicted commits

检查存在冲突的提交

jj log -r 'conflicts()'
jj log -r 'conflicts()'

See conflict details

查看冲突详情

jj st # shows conflict markers jj diff # shows conflicted content
undefined
jj st # 显示冲突标记 jj diff # 显示冲突内容
undefined

Resolving Conflicts

解决冲突

bash
undefined
bash
undefined

Option 1: Edit files directly

选项1:直接编辑文件

Open conflicted files, resolve markers, save

打开冲突文件,解决标记,保存

Option 2: Use resolve command with merge tool

选项2:使用resolve命令和合并工具

jj resolve jj resolve <path> # specific file
jj resolve jj resolve <path> # 指定文件

After resolving, commit is automatically updated

解决后,提交会自动更新

jj st # verify resolved
undefined
jj st # 验证是否已解决
undefined

Conflict Markers

冲突标记

jj uses standard conflict markers in files:
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-old line
+new line from side 1
+++++++ Contents of side #2
new line from side 2
>>>>>>>
jj在文件中使用标准的冲突标记:
<<<<<<< Conflict 1 of 1
%%%%%%% 从基础版本到分支#1的变更
-old line
+new line from side 1
+++++++ 分支#2的内容
new line from side 2
>>>>>>>

Aborting a Conflicted Rebase

中止冲突变基

bash
undefined
bash
undefined

Check operation log

查看操作日志

jj op log
jj op log

Undo the rebase that caused conflicts

撤销导致冲突的变基操作

jj op undo
undefined
jj op undo
undefined

Revsets

版本集(Revsets)

Revsets are expressions for selecting commits. They're used with
-r
flag in many commands.
版本集是用于选择提交的表达式。它们在许多命令中与
-r
标志一起使用。

Basic Revsets

基础版本集

RevsetDescription
@
Working copy commit
@-
Parent of working copy
@--
Grandparent of working copy
<rev>-
Parent of revision
root()
The root commit
heads(all())
All head commits
bookmarks()
All commits with bookmarks
main
Commit at bookmark "main"
main@origin
Remote bookmark
版本集说明
@
工作副本提交
@-
工作副本的父提交
@--
工作副本的祖父提交
<rev>-
指定版本的父提交
root()
根提交
heads(all())
所有头部提交
bookmarks()
所有带有书签的提交
main
书签"main"指向的提交
main@origin
远程书签

Ancestry Operators

祖先操作符

RevsetDescription
::<rev>
Ancestors of rev (inclusive)
<rev>::
Descendants of rev (inclusive)
<rev1>::<rev2>
Commits between rev1 and rev2
::@
All ancestors of working copy
@::
Working copy and all descendants
版本集说明
::<rev>
版本rev的祖先(包含自身)
<rev>::
版本rev的后代(包含自身)
<rev1>::<rev2>
版本rev1和rev2之间的提交
::@
工作副本的所有祖先
@::
工作副本及其所有后代

Set Operations

集合操作

RevsetDescription
<rev1> | <rev2>
Union (either)
<rev1> & <rev2>
Intersection (both)
<rev1> ~ <rev2>
Difference (in rev1, not in rev2)
~<rev>
Negation (not in rev)
版本集说明
<rev1> | <rev2>
并集(任一版本)
<rev1> & <rev2>
交集(两个版本都包含)
<rev1> ~ <rev2>
差集(在rev1中但不在rev2中)
~<rev>
补集(不在rev1中)

Filtering Functions

过滤函数

RevsetDescription
conflicts()
Commits with conflicts
empty()
Empty commits
merges()
Merge commits
description(pattern)
Commits matching description
author(pattern)
Commits by author
committer(pattern)
Commits by committer
file(path)
Commits touching file/path
mine()
Commits by current user
版本集说明
conflicts()
存在冲突的提交
empty()
空提交
merges()
合并提交
description(pattern)
提交信息匹配指定模式的提交
author(pattern)
指定作者的提交
committer(pattern)
指定提交者的提交
file(path)
修改过指定文件/路径的提交
mine()
当前用户的提交

Common Revset Examples

常见版本集示例

bash
undefined
bash
undefined

Show commits not on remote main

显示不在远程main分支上的提交

jj log -r 'main@origin..@'
jj log -r 'main@origin..@'

Show all my commits

显示所有我提交的内容

jj log -r 'mine()'
jj log -r 'mine()'

Show recent commits touching a file

显示最近修改过指定文件的提交

jj log -r 'file("src/main.rs")'
jj log -r 'file("src/main.rs")'

Show commits with "fix" in description

显示提交信息中包含"fix"的提交

jj log -r 'description("fix")'
jj log -r 'description("fix")'

Show all conflicted commits

显示所有存在冲突的提交

jj log -r 'conflicts()'
jj log -r 'conflicts()'

Show commits on current branch not on main

显示当前分支上不在main分支的提交

jj log -r '::@ ~ ::main'
jj log -r '::@ ~ ::main'

Show heads that aren't bookmarks

显示不是书签的头部提交

jj log -r 'heads(all()) ~ bookmarks()'
undefined
jj log -r 'heads(all()) ~ bookmarks()'
undefined

Templates

模板

Templates customize the output of
jj log
,
jj show
, and other commands.
模板用于自定义
jj log
jj show
等命令的输出。

Using Templates

使用模板

bash
undefined
bash
undefined

Basic template usage

基础模板使用

jj log -T '<template>'
jj log -T '<template>'

Common templates

常见模板

jj log -T 'change_id ++ "\n"' jj log -T 'commit_id ++ " " ++ description.first_line() ++ "\n"'
undefined
jj log -T 'change_id ++ "\n"' jj log -T 'commit_id ++ " " ++ description.first_line() ++ "\n"'
undefined

Template Variables

模板变量

VariableDescription
change_id
The change ID
commit_id
The commit ID
description
Full commit description
author
Author information
committer
Committer information
branches
Associated bookmarks
working_copies
Working copy symbol if applicable
empty
Boolean: is commit empty
conflict
Boolean: has conflicts
变量说明
change_id
变更ID
commit_id
提交ID
description
完整提交信息
author
作者信息
committer
提交者信息
branches
关联的书签
working_copies
是否为工作副本的符号
empty
是否为空提交的布尔值
conflict
是否存在冲突的布尔值

Template Methods

模板方法

bash
undefined
bash
undefined

String methods

字符串方法

description.first_line() # first line only commit_id.short() # shortened ID commit_id.short(8) # 8 character ID
description.first_line() # 仅第一行 commit_id.short() # 缩短的ID commit_id.short(8) # 8字符ID

Conditionals

条件判断

if(empty, "[empty]", description.first_line())
if(empty, "[empty]", description.first_line())

Formatting

格式化

separate(" ", change_id.short(), description.first_line())
undefined
separate(" ", change_id.short(), description.first_line())
undefined

Example Templates

示例模板

bash
undefined
bash
undefined

Compact one-liner

紧凑的单行格式

jj log -T 'change_id.short() ++ " " ++ if(description, description.first_line(), "(no description)") ++ "\n"'
jj log -T 'change_id.short() ++ " " ++ if(description, description.first_line(), "(无提交信息)") ++ "\n"'

Show with commit ID

显示提交ID

jj log -T 'commit_id.short(8) ++ " " ++ change_id.short() ++ " " ++ description.first_line() ++ "\n"'
jj log -T 'commit_id.short(8) ++ " " ++ change_id.short() ++ " " ++ description.first_line() ++ "\n"'

Highlight empty/conflict

高亮空提交/冲突

jj log -T 'change_id.short() ++ if(empty, " [empty]") ++ if(conflict, " [CONFLICT]") ++ " " ++ description.first_line() ++ "\n"'
undefined
jj log -T 'change_id.short() ++ if(empty, " [empty]") ++ if(conflict, " [CONFLICT]") ++ " " ++ description.first_line() ++ "\n"'
undefined

Advanced Commands

高级命令

jj split - Divide a Commit

jj split - 拆分提交

Split a commit into multiple smaller commits:
bash
undefined
将一个提交拆分为多个更小的提交:
bash
undefined

Interactive split of current commit

交互式拆分当前提交

jj split
jj split

Split specific commit

拆分指定提交

jj split -r <rev>
jj split -r <rev>

Split by selecting specific files for first commit

通过选择特定文件来拆分第一个提交

jj split path/to/file1 path/to/file2

When run interactively, jj opens an editor to select which changes go into
the first commit. The remaining changes stay in a second commit.
jj split path/to/file1 path/to/file2

以交互式运行时,jj会打开编辑器让你选择哪些变更进入第一个提交。剩余的变更会保留在第二个提交中。

jj fix - Run Formatters

jj fix - 运行格式化工具

Automatically format files according to configured tools:
bash
undefined
根据配置的工具自动格式化文件:
bash
undefined

Fix current commit

修复当前提交

jj fix
jj fix

Fix specific revision

修复指定版本

jj fix -r <rev>
jj fix -r <rev>

Fix range of commits

修复一系列提交

jj fix -s <source> # source and descendants

Configure formatters in `.jj/repo/config.toml`:

```toml
[fix.tools.rustfmt]
command = ["rustfmt", "--emit=stdout"]
patterns = ["glob:'**/*.rs'"]

[fix.tools.prettier]
command = ["prettier", "--write", "--stdin-filepath=$path"]
patterns = ["glob:'**/*.{js,ts,jsx,tsx}'"]
jj fix -s <source> # 源提交及其后代

在`.jj/repo/config.toml`中配置格式化工具:

```toml
[fix.tools.rustfmt]
command = ["rustfmt", "--emit=stdout"]
patterns = ["glob:'**/*.rs'"]

[fix.tools.prettier]
command = ["prettier", "--write", "--stdin-filepath=$path"]
patterns = ["glob:'**/*.{js,ts,jsx,tsx}'"]

jj sign - Sign Commits

jj sign - 签名提交

Cryptographically sign commits using SSH or GPG:
bash
undefined
使用SSH或GPG对提交进行加密签名:
bash
undefined

Sign current commit

签名当前提交

jj sign
jj sign

Sign specific revision

签名指定版本

jj sign -r <rev>
jj sign -r <rev>

Sign a range

签名一系列提交

jj sign -r '<rev1>::<rev2>'

Configure signing in config:

```toml
[signing]
backend = "ssh"                # or "gpg"
key = "~/.ssh/id_ed25519.pub"
jj sign -r '<rev1>::<rev2>'

在配置中设置签名:

```toml
[signing]
backend = "ssh"                # 或 "gpg"
key = "~/.ssh/id_ed25519.pub"

jj bisect - Find Bad Commits

jj bisect - 查找问题提交

Binary search to find which commit introduced a bug:
bash
undefined
通过二分查找定位引入bug的提交:
bash
undefined

Start bisect

开始二分查找

jj bisect start
jj bisect start

Mark current commit as bad

将当前标记为坏提交

jj bisect bad
jj bisect bad

Mark a known good commit

标记一个已知的好提交

jj bisect good <rev>
jj bisect good <rev>

jj checks out middle commit - test it, then:

jj会检出中间提交——测试后执行:

jj bisect good # if it works jj bisect bad # if it's broken
jj bisect good # 如果正常工作 jj bisect bad # 如果存在问题

Repeat until found

重复直到找到问题提交

Reset when done

完成后重置

jj bisect reset

For automated bisect with a test script:

```bash
jj bisect start
jj bisect bad @
jj bisect good <known-good>
jj bisect run ./test-script.sh
jj bisect reset

使用测试脚本进行自动二分查找:

```bash
jj bisect start
jj bisect bad @
jj bisect good <known-good>
jj bisect run ./test-script.sh

Error Recovery

错误恢复

jj maintains a complete operation log, making it easy to recover from mistakes.
jj维护了完整的操作日志,让你可以轻松从错误中恢复。

View Operation History

查看操作历史

bash
undefined
bash
undefined

Show operation log

显示操作日志

jj op log
jj op log

Show detailed operation

显示详细操作信息

jj op show <operation-id>
undefined
jj op show <operation-id>
undefined

Undo Operations

撤销操作

bash
undefined
bash
undefined

Undo the last operation

撤销最后一次操作

jj op undo
jj op undo

Undo multiple operations (go back N steps)

撤销多次操作(回退N步)

jj op undo --at @-- # undo last 2 operations
jj op undo --at @-- # 撤销最后2次操作

Restore to a specific operation

恢复到指定操作的状态

jj op restore <operation-id>
undefined
jj op restore <operation-id>
undefined

Common Recovery Scenarios

常见恢复场景

bash
undefined
bash
undefined

Accidentally abandoned a commit

意外放弃了提交

jj op undo
jj op undo

Bad rebase

错误的变基

jj op undo
jj op undo

Want to see state before last 5 operations

想要查看5次操作前的状态

jj op restore <operation-from-5-ops-ago>
jj op restore <operation-from-5-ops-ago>

Find a lost commit

查找丢失的提交

jj op log # find operation where commit existed jj op restore <operation-id> # restore that state
undefined
jj op log # 查找提交存在时的操作 jj op restore <operation-id> # 恢复到该状态
undefined

The Safety Net

安全保障

Nothing is truly lost in jj. The operation log preserves all states, and you can always restore to any previous point. This makes it safe to experiment with history editing.
在jj中没有真正丢失的内容。操作日志保留了所有状态,你始终可以恢复到任何之前的状态。这让你可以安全地尝试历史编辑。

Best Practices

最佳实践

Commit Messages

提交信息

Use conventional commits format for clarity:
bash
jj describe -m "feat: add user authentication"
jj describe -m "fix: resolve race condition in worker"
jj describe -m "docs: update API documentation"
jj describe -m "refactor: extract validation logic"
jj describe -m "test: add integration tests for auth"
jj describe -m "chore: update dependencies"
Update messages as work evolves -
jj describe
can be run anytime.
使用约定式提交格式以保持清晰:
bash
jj describe -m "feat: 添加用户认证"
jj describe -m "fix: 解决工作线程中的竞态条件"
jj describe -m "docs: 更新API文档"
jj describe -m "refactor: 提取验证逻辑"
jj describe -m "test: 添加认证集成测试"
jj describe -m "chore: 更新依赖"
随着工作推进更新提交信息——你可以随时运行
jj describe

History Hygiene

历史整洁

  • Keep commits atomic: Each commit should do one thing
  • Squash WIP commits before pushing:
    jj squash
  • Write meaningful messages when work is complete, not at start
  • Rebase onto main before pushing to avoid merge commits
  • 保持提交原子化:每个提交应该只做一件事
  • 推送前合并WIP提交:使用
    jj squash
  • 工作完成时编写有意义的信息,而不是开始时
  • 推送前变基到main分支以避免合并提交

Bookmark Naming

书签命名

Use descriptive, prefixed bookmark names:
bash
jj bookmark create feat/user-dashboard
jj bookmark create fix/login-timeout
jj bookmark create refactor/auth-module
jj bookmark create docs/api-reference
jj bookmark create chore/update-deps
使用描述性的、带前缀的书签名称:
bash
jj bookmark create feat/user-dashboard
jj bookmark create fix/login-timeout
jj bookmark create refactor/auth-module
jj bookmark create docs/api-reference
jj bookmark create chore/update-deps

Before Push Checklist

推送前检查清单

bash
undefined
bash
undefined

1. Check for conflicts

1. 检查是否存在冲突

jj log -r 'conflicts()'
jj log -r 'conflicts()'

2. Verify clean status

2. 验证状态是否干净

jj st
jj st

3. Review your changes

3. 查看你的变更

jj log -r '::@ ~ ::main@origin' jj diff -r 'main@origin..@'
jj log -r '::@ ~ ::main@origin' jj diff -r 'main@origin..@'

4. Rebase onto latest main

4. 变基到最新的main分支

jj git fetch jj rebase -d main@origin
jj git fetch jj rebase -d main@origin

5. Squash any fixup commits

5. 合并所有修复提交

jj squash -r <fixup>
jj squash -r <fixup>

6. Push

6. 推送

jj git push -b <bookmark>
undefined
jj git push -b <bookmark>
undefined

Working Copy Discipline

工作副本规范

  • Start new work with
    jj new
    to keep changes isolated
  • Use
    jj describe
    frequently to document what you're doing
  • Don't let the working copy accumulate unrelated changes
  • 使用
    jj new
    开始新工作,保持变更隔离
  • 经常使用
    jj describe
    记录你的工作内容
  • 不要让工作副本积累不相关的变更

Anti-patterns to Avoid

应避免的反模式

Forgetting to Describe

忘记描述提交

bash
undefined
bash
undefined

Bad: Working copy with "(no description set)"

错误:工作副本的提交信息为"(no description set)"

This makes history hard to understand

这会让历史难以理解

Good: Always describe your work

正确:始终描述你的工作

jj describe -m "feat: implementing user preferences"
undefined
jj describe -m "feat: 实现用户偏好设置"
undefined

Massive Commits

超大提交

bash
undefined
bash
undefined

Bad: One huge commit with many unrelated changes

错误:一个包含许多不相关变更的大提交

Good: Split into logical units

正确:拆分为逻辑单元

jj split # separate concerns
undefined
jj split # 分离关注点
undefined

Ignoring Conflicts

忽略冲突

bash
undefined
bash
undefined

Bad: Leaving conflicts unresolved

错误:留下未解决的冲突

jj log -r 'conflicts()' # shows conflicted commits
jj log -r 'conflicts()' # 显示存在冲突的提交

Good: Resolve conflicts promptly

正确:及时解决冲突

jj resolve
jj resolve

or undo the operation that caused them

或撤销导致冲突的操作

jj op undo
undefined
jj op undo
undefined

Not Fetching Before Push

推送前不拉取

bash
undefined
bash
undefined

Bad: Push without checking remote state

错误:不检查远程状态就推送

jj git push -b feature
jj git push -b feature

Good: Always fetch and rebase first

正确:始终先拉取再变基

jj git fetch jj rebase -d main@origin jj git push -b feature
undefined
jj git fetch jj rebase -d main@origin jj git push -b feature
undefined

Using Commit IDs Instead of Change IDs

使用提交ID而非变更ID

bash
undefined
bash
undefined

Bad: Using commit IDs (change on rewrite)

错误:使用提交ID(重写后会改变)

jj edit abc123def
jj edit abc123def

Good: Using change IDs (stable)

正确:使用变更ID(保持稳定)

jj edit kpqxywon
undefined
jj edit kpqxywon
undefined

Working Directly on main

直接在main分支工作

bash
undefined
bash
undefined

Bad: Making changes directly on main

错误:直接在main分支进行变更

jj edit main
jj edit main

... make changes ...

... 进行变更 ...

Good: Create a new commit for work

正确:为工作创建新提交

jj new main -m "feat: my feature" jj bookmark create feat/my-feature
undefined
jj new main -m "feat: 我的新功能" jj bookmark create feat/my-feature
undefined

Quick Reference

快速参考

Most Common Commands

最常用命令

CommandDescription
jj st
Show status
jj log
Show commit graph
jj diff
Show working copy diff
jj new
Create new commit
jj describe -m "msg"
Set commit message
jj commit -m "msg"
Describe and create new commit
jj squash
Squash into parent
jj rebase -d <dest>
Rebase to destination
jj git fetch
Fetch from remote
jj git push -b <name>
Push bookmark
jj op undo
Undo last operation
命令说明
jj st
显示状态
jj log
显示提交图
jj diff
显示工作副本的变更
jj new
创建新提交
jj describe -m "msg"
设置提交信息
jj commit -m "msg"
描述提交并创建新工作副本
jj squash
合并到父提交
jj rebase -d <dest>
变基到目标
jj git fetch
从远程拉取
jj git push -b <name>
推送书签
jj op undo
撤销最后一次操作

Revision Shortcuts

版本快捷方式

ShortcutMeaning
@
Working copy
@-
Parent of @
@--
Grandparent of @
main
The main bookmark
main@origin
Remote main
快捷方式含义
@
工作副本
@-
@的父提交
@--
@的祖父提交
main
main书签
main@origin
远程main分支

Getting Help

获取帮助

bash
jj help                        # general help
jj help <command>              # command-specific help
jj help revsets                # revset syntax help
jj help templates              # template syntax help
bash
jj help                        # 通用帮助
jj help <command>              # 命令专属帮助
jj help revsets                # 版本集语法帮助
jj help templates              # 模板语法帮助