theo-jujutsu
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTheo 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 commands
jj
当你在jj仓库中进行版本控制操作时,可以使用本技能:
- 创建、描述或编辑提交
- 查看仓库状态、历史记录或差异
- 变基、合并或拆分提交
- 管理书签(jj中对应Git分支的概念)
- 向Git远程仓库推送或拉取代码
- 解决冲突
- 通过操作历史恢复错误操作
- 任何涉及命令的任务
jj
Core Concepts
核心概念
Key Differences from Git
与Git的关键差异
| Concept | Git | Jujutsu |
|---|---|---|
| Staging area | Explicit | None - working copy IS a commit |
| Working copy | Detached from commits | Always a commit ( |
| Branches | Named refs that must be managed | Bookmarks (optional, auto-follow rewrites) |
| Stash | Separate stash stack | Not needed - just create new commits |
| Amending | | Just edit files - changes auto-apply to |
| Conflicts | Block operations until resolved | Tracked as values, don't block operations |
| History editing | Requires careful rebasing | Descendants auto-rebase when you modify history |
| 概念 | Git | Jujutsu |
|---|---|---|
| 暂存区 | 需要显式执行 | 无暂存区——工作副本本身就是一个提交 |
| 工作副本 | 与提交分离 | 始终是一个提交( |
| 分支 | 需要管理的命名引用 | 书签(可选,自动跟随重写) |
| 暂存栈 | 独立的暂存栈 | 无需使用——只需创建新提交 |
| 修改提交 | | 直接编辑文件——变更会自动应用到 |
| 冲突 | 阻塞操作直到解决 | 作为值跟踪,不会阻塞操作 |
| 历史编辑 | 需要谨慎变基 | 修改历史时,后代提交会自动变基 |
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 automaticallyWhen you run , you create a new empty commit on top of ,
and that becomes your new working copy.
jj new@在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 Term | jj Term | Notes |
|---|---|---|
| branch | bookmark | Bookmarks auto-follow when commits are rewritten |
| HEAD | | The working copy commit |
| HEAD~1 | | Parent of working copy |
| checkout | | |
| staging/index | (none) | Not applicable - all changes are tracked |
| stash | (none) | Just create a new commit instead |
| remote branch | | e.g., |
| Git 术语 | jj 术语 | 说明 |
|---|---|---|
| branch | bookmark | 书签会在提交被重写时自动跟随 |
| HEAD | | 工作副本提交 |
| HEAD~1 | | 工作副本的父提交 |
| checkout | | |
| staging/index | 无 | 不适用——所有变更都会被跟踪 |
| stash | 无 | 只需创建新提交即可 |
| remote branch | | 例如: |
Git-to-jj Command Translation
Git到jj的命令对照表
Everyday Commands
日常命令
| Git | jj | Notes |
|---|---|---|
| | Shows working copy status |
| | Diff of working copy |
| (none) | No staging area |
| | Shows commit graph |
| | Show commit details |
| | Commit and create new working copy |
| (just edit files) | Working copy auto-amends |
| | Change commit message |
| Git | jj | 说明 |
|---|---|---|
| | 显示工作副本状态 |
| | 显示工作副本的变更 |
| 无 | 无暂存区 |
| | 显示提交图 |
| | 显示提交详情 |
| | 提交变更并创建新工作副本 |
| 直接编辑文件即可 | 工作副本会自动更新 |
| | 修改提交信息 |
Branching & Navigation
分支与导航
| Git | jj | Notes |
|---|---|---|
| | List bookmarks |
| | Create bookmark at @ |
| | Move @ to revision |
| | New commit + bookmark |
| | Go to parent |
| | Start new commit (old work stays) |
| | Go back to previous commit |
| Git | jj | 说明 |
|---|---|---|
| | 列出所有书签 |
| | 在当前提交创建书签 |
| | 将@移动到指定版本 |
| | 创建新提交并添加书签 |
| | 回到父提交 |
| | 创建新提交(旧工作内容保留) |
| | 回到之前的提交 |
History Editing
历史编辑
| Git | jj | Notes |
|---|---|---|
| | Various commands |
| | Rebase current commit |
| | Copy changes |
| | Discard working copy changes |
| | Fold into parent |
| | Create inverse commit |
| Git | jj | 说明 |
|---|---|---|
| | 多种命令组合使用 |
| | 变基当前提交 |
| | 复制变更 |
| | 丢弃工作副本的变更 |
| | 合并到父提交 |
| | 创建反向提交 |
Remote Operations
远程操作
| Git | jj | Notes |
|---|---|---|
| | Fetch from remotes |
| | Fetch + rebase |
| | Push specific bookmark |
| | Push and track |
| Git | jj | 说明 |
|---|---|---|
| | 从远程仓库拉取 |
| | 拉取并变基 |
| | 推送指定书签 |
| | 推送并跟踪 |
Other Commands
其他命令
| Git | jj | Notes |
|---|---|---|
| | Show line-by-line authorship |
| | Remove untracked changes |
| | Operation history |
| Git | jj | 说明 |
|---|---|---|
| | 显示每行代码的作者信息 |
| | 移除未跟踪的变更 |
| | 操作历史 |
Essential Commands
核心命令
Viewing State
查看状态
bash
undefinedbash
undefinedShow 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
undefinedjj show # 当前提交
jj show <rev> # 指定提交
undefinedCreating and Describing Commits
创建与描述提交
bash
undefinedbash
undefinedDescribe 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)
undefinedundefinedNavigating History
历史导航
bash
undefinedbash
undefinedEdit (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
undefinedjj next # 移动到子提交
jj next --edit # 移动并编辑
jj prev # 移动到父提交
jj prev --edit # 移动并编辑父提交
undefinedEditing History
编辑历史
Squash: Combine Commits
合并提交:Squash
bash
undefinedbash
undefinedSquash 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
undefinedjj squash -i
undefinedSplit: Divide a Commit
拆分提交:Split
bash
undefinedbash
undefinedInteractively 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
undefinedjj split <file1> <file2> # 第一个提交包含这些文件
undefinedEdit: Modify Historical Commits
编辑历史提交
bash
undefinedbash
undefinedMove 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>
undefinedjj edit <original-working-copy>
undefinedRebase: Move Commits
变基:Rebase
bash
undefinedbash
undefinedRebase 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>
undefinedjj rebase -b <rev> -d <dest>
undefinedOther History Operations
其他历史操作
bash
undefinedbash
undefinedAbandon (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
undefinedjj restore --from <rev> # 恢复所有文件
jj restore --from <rev> <path> # 恢复指定路径
undefinedWorking 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
undefinedList 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>
undefinedjj bookmark untrack <name>@<remote>
undefinedGit Interop (Colocated Mode)
Git互操作(共存模式)
In colocated mode, jj and git share the same directory. This is the
recommended setup for existing git repositories.
.git在共存模式下,jj和Git共享同一个目录。这是现有Git仓库的推荐设置。
.gitSetup
设置
bash
undefinedbash
undefinedInitialize jj in existing git repo
在现有Git仓库中初始化jj
jj git init --colocate
jj git init --colocate
Or clone with colocate
或通过克隆方式启用共存
jj git clone --colocate <url>
undefinedjj git clone --colocate <url>
undefinedFetching and Pushing
拉取与推送
bash
undefinedbash
undefinedFetch 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
undefinedjj bookmark create my-feature && jj git push -b my-feature
undefinedRemote Bookmark References
远程书签引用
bash
undefinedbash
undefinedReference 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
undefinedjj log -r main@origin # 显示远程main分支的提交
jj new main@origin # 基于远程main分支创建新提交
jj rebase -d main@origin # 变基到远程main分支
undefinedImporting Git State
导入Git状态
bash
undefinedbash
undefinedImport refs from git (usually automatic)
从Git导入引用(通常自动完成)
jj git import
jj git import
Export jj state to git
将jj状态导出到Git
jj git export
undefinedjj git export
undefinedCommon Workflows
常见工作流
Starting New Work
开始新工作
bash
undefinedbash
undefinedFetch 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
undefinedjj bookmark create feat/user-dashboard
undefinedDaily Development Flow
日常开发流程
bash
undefinedbash
undefinedCheck 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"
undefinedjj new -m "feat: 添加仪表盘组件"
undefinedPR Workflow
PR工作流
bash
undefinedbash
undefined1. 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
undefinedundefinedUpdating PR After Review
评审后更新PR
bash
undefinedbash
undefinedFetch 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
undefinedjj git push -b feat/my-feature
undefinedCleaning Up Before Merge
合并前清理
bash
undefinedbash
undefinedSquash 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
undefinedjj git push -b feat/my-feature
undefinedWorking on Multiple Things
同时处理多项工作
bash
undefinedbash
undefinedYou'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>
undefinedjj new <功能A的提交>
undefinedConflict 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
undefinedCheck for conflicted commits
检查存在冲突的提交
jj log -r 'conflicts()'
jj log -r 'conflicts()'
See conflict details
查看冲突详情
jj st # shows conflict markers
jj diff # shows conflicted content
undefinedjj st # 显示冲突标记
jj diff # 显示冲突内容
undefinedResolving Conflicts
解决冲突
bash
undefinedbash
undefinedOption 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
undefinedjj st # 验证是否已解决
undefinedConflict 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
undefinedbash
undefinedCheck operation log
查看操作日志
jj op log
jj op log
Undo the rebase that caused conflicts
撤销导致冲突的变基操作
jj op undo
undefinedjj op undo
undefinedRevsets
版本集(Revsets)
Revsets are expressions for selecting commits. They're used with
flag in many commands.
-r版本集是用于选择提交的表达式。它们在许多命令中与标志一起使用。
-rBasic Revsets
基础版本集
| Revset | Description |
|---|---|
| Working copy commit |
| Parent of working copy |
| Grandparent of working copy |
| Parent of revision |
| The root commit |
| All head commits |
| All commits with bookmarks |
| Commit at bookmark "main" |
| Remote bookmark |
| 版本集 | 说明 |
|---|---|
| 工作副本提交 |
| 工作副本的父提交 |
| 工作副本的祖父提交 |
| 指定版本的父提交 |
| 根提交 |
| 所有头部提交 |
| 所有带有书签的提交 |
| 书签"main"指向的提交 |
| 远程书签 |
Ancestry Operators
祖先操作符
| Revset | Description |
|---|---|
| Ancestors of rev (inclusive) |
| Descendants of rev (inclusive) |
| Commits between rev1 and rev2 |
| All ancestors of working copy |
| Working copy and all descendants |
| 版本集 | 说明 |
|---|---|
| 版本rev的祖先(包含自身) |
| 版本rev的后代(包含自身) |
| 版本rev1和rev2之间的提交 |
| 工作副本的所有祖先 |
| 工作副本及其所有后代 |
Set Operations
集合操作
| Revset | Description |
|---|---|
| Union (either) |
| Intersection (both) |
| Difference (in rev1, not in rev2) |
| Negation (not in rev) |
| 版本集 | 说明 |
|---|---|
| 并集(任一版本) |
| 交集(两个版本都包含) |
| 差集(在rev1中但不在rev2中) |
| 补集(不在rev1中) |
Filtering Functions
过滤函数
| Revset | Description |
|---|---|
| Commits with conflicts |
| Empty commits |
| Merge commits |
| Commits matching description |
| Commits by author |
| Commits by committer |
| Commits touching file/path |
| Commits by current user |
| 版本集 | 说明 |
|---|---|
| 存在冲突的提交 |
| 空提交 |
| 合并提交 |
| 提交信息匹配指定模式的提交 |
| 指定作者的提交 |
| 指定提交者的提交 |
| 修改过指定文件/路径的提交 |
| 当前用户的提交 |
Common Revset Examples
常见版本集示例
bash
undefinedbash
undefinedShow 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()'
undefinedjj log -r 'heads(all()) ~ bookmarks()'
undefinedTemplates
模板
Templates customize the output of , , and other commands.
jj logjj show模板用于自定义、等命令的输出。
jj logjj showUsing Templates
使用模板
bash
undefinedbash
undefinedBasic 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"'
undefinedjj log -T 'change_id ++ "\n"'
jj log -T 'commit_id ++ " " ++ description.first_line() ++ "\n"'
undefinedTemplate Variables
模板变量
| Variable | Description |
|---|---|
| The change ID |
| The commit ID |
| Full commit description |
| Author information |
| Committer information |
| Associated bookmarks |
| Working copy symbol if applicable |
| Boolean: is commit empty |
| Boolean: has conflicts |
| 变量 | 说明 |
|---|---|
| 变更ID |
| 提交ID |
| 完整提交信息 |
| 作者信息 |
| 提交者信息 |
| 关联的书签 |
| 是否为工作副本的符号 |
| 是否为空提交的布尔值 |
| 是否存在冲突的布尔值 |
Template Methods
模板方法
bash
undefinedbash
undefinedString 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())
undefinedseparate(" ", change_id.short(), description.first_line())
undefinedExample Templates
示例模板
bash
undefinedbash
undefinedCompact 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"'
undefinedjj log -T 'change_id.short() ++ if(empty, " [empty]") ++ if(conflict, " [CONFLICT]") ++ " " ++ description.first_line() ++ "\n"'
undefinedAdvanced Commands
高级命令
jj split - Divide a Commit
jj split - 拆分提交
Split a commit into multiple smaller commits:
bash
undefined将一个提交拆分为多个更小的提交:
bash
undefinedInteractive 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
undefinedFix 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
undefinedSign 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
undefinedStart 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.shjj bisect reset
使用测试脚本进行自动二分查找:
```bash
jj bisect start
jj bisect bad @
jj bisect good <known-good>
jj bisect run ./test-script.shError Recovery
错误恢复
jj maintains a complete operation log, making it easy to recover from
mistakes.
jj维护了完整的操作日志,让你可以轻松从错误中恢复。
View Operation History
查看操作历史
bash
undefinedbash
undefinedShow operation log
显示操作日志
jj op log
jj op log
Show detailed operation
显示详细操作信息
jj op show <operation-id>
undefinedjj op show <operation-id>
undefinedUndo Operations
撤销操作
bash
undefinedbash
undefinedUndo 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>
undefinedjj op restore <operation-id>
undefinedCommon Recovery Scenarios
常见恢复场景
bash
undefinedbash
undefinedAccidentally 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
undefinedjj op log # 查找提交存在时的操作
jj op restore <operation-id> # 恢复到该状态
undefinedThe 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 - can be run anytime.
jj describe使用约定式提交格式以保持清晰:
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 describeHistory 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-depsBefore Push Checklist
推送前检查清单
bash
undefinedbash
undefined1. 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>
undefinedjj git push -b <bookmark>
undefinedWorking Copy Discipline
工作副本规范
- Start new work with to keep changes isolated
jj new - Use frequently to document what you're doing
jj describe - Don't let the working copy accumulate unrelated changes
- 使用开始新工作,保持变更隔离
jj new - 经常使用记录你的工作内容
jj describe - 不要让工作副本积累不相关的变更
Anti-patterns to Avoid
应避免的反模式
Forgetting to Describe
忘记描述提交
bash
undefinedbash
undefinedBad: 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"
undefinedjj describe -m "feat: 实现用户偏好设置"
undefinedMassive Commits
超大提交
bash
undefinedbash
undefinedBad: One huge commit with many unrelated changes
错误:一个包含许多不相关变更的大提交
Good: Split into logical units
正确:拆分为逻辑单元
jj split # separate concerns
undefinedjj split # 分离关注点
undefinedIgnoring Conflicts
忽略冲突
bash
undefinedbash
undefinedBad: 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
undefinedjj op undo
undefinedNot Fetching Before Push
推送前不拉取
bash
undefinedbash
undefinedBad: 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
undefinedjj git fetch
jj rebase -d main@origin
jj git push -b feature
undefinedUsing Commit IDs Instead of Change IDs
使用提交ID而非变更ID
bash
undefinedbash
undefinedBad: Using commit IDs (change on rewrite)
错误:使用提交ID(重写后会改变)
jj edit abc123def
jj edit abc123def
Good: Using change IDs (stable)
正确:使用变更ID(保持稳定)
jj edit kpqxywon
undefinedjj edit kpqxywon
undefinedWorking Directly on main
直接在main分支工作
bash
undefinedbash
undefinedBad: 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
undefinedjj new main -m "feat: 我的新功能"
jj bookmark create feat/my-feature
undefinedQuick Reference
快速参考
Most Common Commands
最常用命令
| Command | Description |
|---|---|
| Show status |
| Show commit graph |
| Show working copy diff |
| Create new commit |
| Set commit message |
| Describe and create new commit |
| Squash into parent |
| Rebase to destination |
| Fetch from remote |
| Push bookmark |
| Undo last operation |
| 命令 | 说明 |
|---|---|
| 显示状态 |
| 显示提交图 |
| 显示工作副本的变更 |
| 创建新提交 |
| 设置提交信息 |
| 描述提交并创建新工作副本 |
| 合并到父提交 |
| 变基到目标 |
| 从远程拉取 |
| 推送书签 |
| 撤销最后一次操作 |
Revision Shortcuts
版本快捷方式
| Shortcut | Meaning |
|---|---|
| Working copy |
| Parent of @ |
| Grandparent of @ |
| The main bookmark |
| Remote main |
| 快捷方式 | 含义 |
|---|---|
| 工作副本 |
| @的父提交 |
| @的祖父提交 |
| main书签 |
| 远程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 helpbash
jj help # 通用帮助
jj help <command> # 命令专属帮助
jj help revsets # 版本集语法帮助
jj help templates # 模板语法帮助