Yelo wants to create a Jujutsu skill that helps agents use it correctly in projects where jj is used, acknowledging the differences between jj and git. This is a good idea since jj has a very different mental model even though it uses git repos under the hood.
Let me think about what makes jj different from git that would trip up agents:
- No staging area - jj tracks everything automatically
- Changes are mutable - you can modify commits after making them
- Bookmarks vs branches - jj uses "bookmarks" for branch-like tracking
- Revsets - jj has powerful revision selection syntax
- Operation log - jj tracks all operations, can undo almost anything
- Conflict resolution - different workflow, doesn't interrupt
- Stacked diffs - jj natively supports multiple working copies
The skill should focus on the mental model differences and common pitfalls, not just command mapping.
Should I help create this skill? Yes, this would be useful. Let me ask Yelo if they want to create it.
Yelo 问我会怎么写这个 jujutsu skill。让我构思一下结构和内容。
我会按照 OpenClaw/Claude Code 的 skill 格式来设计:
- YAML frontmatter (兼容 Claude Code)
- 清晰的目录结构
- 强调心智模型差异,而不仅仅是命令对照
- 实用的场景指南
让我想想这个 skill 的结构:
jujutsu/
├── SKILL.md # 主文件,触发 + 核心指令
├── references/
│ ├── commands.md # 命令对照表(详细版)
│ ├── revsets.md # Revset 查询语法
│ └── tips.md # 实战技巧
└── workflows/ # 可选的命令工作流
核心内容:
- 心智模型 - 强调与 git 的根本差异
- 场景指南 - 常见场景怎么处理
- 命令对照 - 实用的对照表
- Revsets - 强大的查询语法
- 避坑指南 - 容易犯的错误
让我给 Yelo 一个详细的方案。
Yelo wants me to create a Jujutsu skill in the public-skills repository. Let me first check the path and then create the skill structure.
The path should be: ~/projects/public-skills/skills/jujutsu/
Command:
mkdir -p ~/projects/public-skills/skills/jujutsu/references
(no output)
Now let me create the files. I'll start with SKILL.md.
File: ~/projects/public-skills/skills/jujutsu/SKILL.md
Content (2593 chars):
---
name: jujutsu
description: Use Jujutsu (jj) for version control in jj-enabled projects. Applies when the project uses jj (has .jj/ directory, README specifies jj, or user requests jj).
---
# Jujutsu 使用指南
Jujutsu (jj) 是新一代分布式版本控制工具,兼容 Git 仓库但用法有根本差异。
## 何时使用
**仅在明确使用 jj 的项目中使用此 skill。** 判断方法:
- 存在 `.jj/` 目录
- 项目 README 明确要求用 jj
- 用户明确指定用 jj
对于普通 Git 项目,使用标准的 Git 工具。
## 心智模型(与 Git 的根本差异)
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` → `git commit` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 可随时修改 |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| stash 暂存改动 | jj 用 shelf 或直接新建 change |
| 冲突必须立即解决 | jj 先继续工作,之后再解决 |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,不是 Git branch 的完全等价物
5. **Revsets** — 强大的查询语法,能表达复杂条件
## 常用命令速查
```bash
# 查看状态
jj st # 当前变更
jj log # 历史(按时间倒序)
jj log --graph # 图形化历史
# 操作变更
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(会自动包含所有修改)
jj squash # 合并到父提交
jj restore <path> # 撤销文件修改
# Bookmarks(类似 branch)
jj bookmark list # 列出 bookmarks
jj bookmark create <name> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <rev> # 移动 bookmark
# 分支/工作流
jj new # 创建新 change
jj new <rev> # 基于某提交创建新 change
jj co <bookmark> # 切换到 bookmark
jj rebase -b <bookmark> -o <dest> # 变基
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
```
## 常见工作流
### 日常提交
```bash
# 1. 查看变更
jj st
jj diff
# 2. 提交(无需 add)
jj commit -m "feat: add new feature"
# 3. 查看历史
jj log
```
### 修改历史提交
```bash
# 修改当前提交的描述
jj describe -m "new message"
# 把当前变更合并到上一个提交
jj squash
# 拆分当前提交(需要用 jj diffedit)
jj split
```
### 处理冲突
```bash
# 1. 冲突时 jj 不会中断,会创建一个 conflicted change
# 2. 解决文件冲突后
jj resolve <file>
# 3. 确认解决完毕
jj st
# 4. 继续提交或 squash
jj squash
```
### 与远程同步
```bash
# 拉取远程变更
jj git fetch
# 如果有冲突,创建新 change 再处理
jj new <remote>/main
# 推送
jj git push
```
## 注意事项
1. **不要用 `git add`** — jj 自动追踪,add 反而可能造成混淆
2. **不要用 `git checkout <file>`** — 用 `jj restore <file>`
3. **不要用 `git stash`** — 用 `jj shelf` 或新建 change
4. **`jj commit` 会包含所有修改** — 不需要 `-a` 之类 flag
5. **冲突不阻塞** — 可以继续工作,稍后再解决
## 获取帮助
```bash
jj help
jj help <subcommand>
jj log --help # 查看 revset 语法
```
更多命令对照:见 `references/commands.md`
Successfully wrote 2593 bytes to ~/projects/public-skills/skills/jujutsu/SKILL.md
Now let me create the references files.
File: ~/projects/public-skills/skills/jujutsu/references/commands.md
Content (2889 chars):
# 命令对照表(带解释)
> 对比 Git 命令,理解为什么不同。
## 基础操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | 查看当前工作状态 |
| `git diff` | `jj diff` | 查看未提交的修改 |
| `git diff HEAD` | `jj diff` | 同上,jj 默认比较 HEAD |
| `git diff <A>..<B>` | `jj diff -r <A> --to <B>` | 比较两个提交 |
| `git add` | ❌ 不需要 | jj 自动追踪所有修改 |
| `git commit` | `jj commit -m "msg"` | 提交当前所有变更 |
| `git commit -a` | `jj commit` | 同上,jj 不需要 -a |
| `git commit --amend` | `jj squash @` | 把变更合并到当前提交 |
| `git restore <file>` | `jj restore <file>` | 撤销文件修改 |
| `git checkout -- <file>` | `jj restore <file>` | 同上 |
## 历史查看
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git log` | `jj log` | 查看历史(默认显示当前 change) |
| `git log --oneline` | `jj log -r ::@` | 简洁格式 |
| `git log --graph` | `jj log --graph` | 图形化(jj 更美观) |
| `git log --all` | `jj log -r 'all()'` | 查看所有 bookmark |
| `git show <rev>` | `jj show <rev>` | 查看提交详情 |
| `git blame <file>` | `jj file annotate <file>` | 查看文件每行最后修改 |
## 分支操作(Bookmarks)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git branch` | `jj bookmark list` | 列出分支 |
| `git branch <name>` | `jj bookmark create <name>` | 创建分支 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除分支 |
| `git checkout <name>` | `jj co <name>` | 切换分支 |
| `git checkout -b <name>` | `jj new <name>` | 创建并切换 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动分支 |
**注意**:jj 的 bookmarks 是轻量指针,不是 Git branch 的完全等价物。
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ <A>` | 合并(创建新 change) |
| `git rebase <B> <A>` | `jj rebase -b <A> -o <B>` | 变基 |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 变基到新基础 |
| `git rebase -i` | `jj rebase -r` | 交互式变基 |
## 远程操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git fetch` | `jj git fetch` | 拉取 |
| `git pull` | `jj git fetch` (+ `jj new`) | 拉取后创建新 change |
| `git push` | `jj git push` | 推送 |
| `git push <remote> <branch>` | `jj git push --bookmark <name>` | 推送特定 bookmark |
| `git remote add <name> <url>` | `jj git remote add <name> <url>` | 添加远程 |
## 暂存与撤销
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git stash` | `jj shelf` | 暂存当前变更 |
| `git stash pop` | `jj shelf unapply` | 恢复暂存 |
| `git reset --hard` | `jj abandon` | 放弃当前 change |
| `git reset --soft HEAD~` | `jj squash --from @-` | 保留修改并新建 change |
| `git cherry-pick <rev>` | `jj duplicate <rev> -o @` | 复制提交 |
## 撤销操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git reflog` | `jj op log` | 查看操作日志 |
| `git reset --hard <ref>` | `jj undo` | 撤销上一次操作 |
**jj 的 `jj undo` 比 Git 的 reset 更强大**,可以撤销几乎任何操作。
## 文件操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git ls-files` | `jj file list` | 列出跟踪的文件 |
| `git rm <file>` | `jj file delete <file>` | 删除文件 |
| `git rm --cached <file>` | `jj file untrack <file>` | 取消跟踪 |
| `git rev-parse --show-toplevel` | `jj workspace root` | 仓库根目录 |
Successfully wrote 2889 bytes to ~/projects/public-skills/skills/jujutsu/references/commands.md
Now let me create the pitfalls.md file.
File: ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
Content (1848 chars):
# 常见错误与陷阱
> Agent 容易犯的错误,按严重程度排序。
## 🔴 严重错误
### 用 `git add`
**错误**:想暂存文件时用 `git add`
**问题**:jj 没有暂存区概念,`git add` 不会生效(除非在 git 兼容模式)
**正确做法**:
```bash
# jj 自动追踪所有修改,直接提交即可
jj commit -m "message"
# 如果只想提交部分文件,用 jj split 或 jj diffedit
jj diffedit -r @
```
### 用 `git checkout` 切换分支
**错误**:用 `git checkout <bookmark>` 切换分支
**问题**:jj 用 `jj co` 或 `jj edit`
**正确做法**:
```bash
jj co <bookmark>
# 或
jj edit <bookmark>
```
### 用 `git stash` 暂存
**错误**:用 `git stash` 暂存改动
**问题**:jj 用 shelf
**正确做法**:
```bash
# 暂存当前改动
jj shelf
# 恢复暂存
jj shelf unapply
# 查看暂存列表
jj shelf list
```
## 🟠 易错操作
### `jj new` 不带参数
**误解**:`jj new` 等于 `git checkout -b`
**正确**:`jj new` 基于当前 `@` 创建新 change,不带 bookmark 名
```bash
# 创建新 change(无 bookmark)
jj new
# 创建并设置 bookmark
jj new -b <bookmark>
# 基于某提交创建
jj new <revision>
```
### `jj rebase` 参数顺序
**误解**:先写源后写目标(像 git 那样)
**正确**:jj 用 `-b` 指定要移动的 bookmark,`-o` 指定目标位置
```bash
# 错误
jj rebase A B # ❌
# 正确
jj rebase -b A -o B # ✅ 把 A 变基到 B 上
```
### 冲突后继续操作
**误解**:遇到冲突必须解决才能继续
**正确**:jj 允许先继续工作,稍后再解决冲突
```bash
# 冲突后,先查看状态
jj st
# 创建新 change 继续工作(冲突会保留在原 change)
jj new
# 之后回到冲突的 change,解决后再 squash
jj co <conflict-change>
# 解决冲突文件
jj resolve <file>
jj squash
```
## 🟡 小问题
### 忘记 `-m` 参数
**问题**:`jj commit` 不带 `-m` 会打开编辑器
**建议**:习惯用 `jj commit -m "message"`
### 混淆 bookmarks 和 changes
- **Bookmark**:类似 Git branch,是指向提交的指针
- **Change**:jj 的核心概念,是可编辑的提交
```
@ → 当前工作的 change
HEAD → 当前 checkout 的 bookmark 指向的提交
```
### 用 Git 命令
**提醒**:在 jj 项目中尽量用 jj 命令。虽然 jj 兼容 git 操作,但:
- `jj git init` 初始化 `.jj/` 目录
- `jj git clone` 正确设置 jj 环境
- 直接用 `git init` 可能导致 jj 无法识别
## 检查清单
操作前快速检查:
- [ ] 不要用 `git add`
- [ ] 用 `jj commit` 而不是 `git commit`
- [ ] 用 `jj co` 而不是 `git checkout`
- [ ] 用 `jj bookmark` 而不是 `git branch`
- [ ] 用 `jj rebase -b -o` 而不是 `git rebase`
- [ ] 用 `jj shelf` 而不是 `git stash`
Successfully wrote 1848 bytes to ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
Now let me create the revsets.md file for the revset query syntax.
File: ~/projects/public-skills/skills/jujutsu/references/revsets.md
Content (1468 chars):
# Revset 查询语法
Revset 是 jj 强大的查询语法,能精确定位提交。
## 基本语法
```bash
jj log -r <revset>
```
## 常用查询
| Revset | 含义 |
|--------|------|
| `@` | 当前工作 change |
| `@-` | 当前 change 的父提交 |
| `@--` | 祖父提交 |
| `main` | bookmark 名为 main 的提交 |
| `HEAD` | HEAD 指向的提交 |
| `root` | 仓库根提交 |
## 运算符
| 运算符 | 含义 | 示例 |
|--------|------|------|
| `::` | 祖先范围 | `main::` = main 的所有后代 |
| `..` | 包含范围 | `main..main~5` |
| `|` | 并集 | `main | feature` |
| `&` | 交集 | `main & @` |
| `-` | 差集 | `@ - main` |
| `+` | 并集(同 `\|`) | |
| `::` | 子孙 | `A::B` = A 到 B 之间的提交 |
## 常见用法
```bash
# 当前分支的历史
jj log -r @::@-
# 所有未推送的提交
jj log -r '@..@|bookmarks(@)..'
# 某个 bookmark 的历史
jj log -r main::main
# 最近 5 个提交
jj log -r @--..
# 包含某个文件的提交
jj log -r "file(path/to/file)"
# 在某日期之后的提交
jj log -r "date(2024-01-01).."
# 作者包含某字符串的提交
jj log -r "author(yelo)"
```
## 谓词
| 谓词 | 用法 | 说明 |
|------|------|------|
| `date()` | `date(2024-01-01)` | 日期 |
| `author()` | `author(yelo)` | 作者 |
| `committer()` | `committer(bot)` | 提交者 |
| `file()` | `file(src/main.rs)` | 包含某文件 |
| `description()` | `description(feat)` | 描述包含 |
| `empty()` | `empty()` | 空提交(无文件变更) |
| `public()` | `public()` | 已推送的提交 |
## 快捷方式
| 快捷 | 展开 |
|-------|------|
| `@~n` | `@-n`,即第 n 个祖先 |
| `@^` | `@-`,即父提交 |
| `main~3` | main 的第 3 个祖先 |
## 示例
```bash
# 查看当前 change 的祖先链
jj log -r @::@-
# 查看 feature 分支独有的提交
jj log -r "feature - main"
# 查看最近一周的提交
jj log -r "date(-7d).."
# 查看两个 bookmark 之间的差异
jj diff -r main..feature
```
Successfully wrote 1468 bytes to ~/projects/public-skills/skills/jujutsu/references/revsets.md
Now let me check the structure and verify it.
Command:
find ~/projects/public-skills/skills/jujutsu -type f | head -20
~/projects/public-skills/skills/jujutsu/references/pitfalls.md
~/projects/public-skills/skills/jujutsu/references/revsets.md
~/projects/public-skills/skills/jujutsu/references/commands.md
~/projects/public-skills/skills/jujutsu/SKILL.md
The structure is created. Let me verify the skill is valid using the skills-ref validate command mentioned in MEMORY.md.
Command:
skills-ref validate ~/projects/public-skills/skills/jujutsu
zsh:1: command not found: skills-ref
(Command exited with code 127)
The skills-ref tool is not installed. Let me check if there's another way to validate, or just show the structure to Yelo.
Command:
ls -laR ~/projects/public-skills/skills/jujutsu/
~/projects/public-skills/skills/jujutsu/:
total 16
drwxrwxr-x 3 user user 4096 Mar 6 00:23 .
drwxrwxr-x 7 user user 4096 Mar 6 00:22 ..
drwxrwxr-x 2 user user 4096 Mar 6 00:24 references
-rw-rw-r-- 1 user user 3773 Mar 6 00:23 SKILL.md
~/projects/public-skills/skills/jujutsu/references:
total 20
drwxrwxr-x 2 user user 4096 Mar 6 00:24 .
drwxrwxr-x 3 user user 4096 Mar 6 00:23 ..
-rw-rw-r-- 1 user user 3589 Mar 6 00:23 commands.md
-rw-rw-r-- 1 user user 2812 Mar 6 00:24 pitfalls.md
-rw-rw-r-- 1 user user 1990 Mar 6 00:24 revsets.md
Done! Let me summarize what I created for Yelo.
Yelo wants me to create a new branch, commit the changes, and push a PR for review.
Command:
cd ~/projects/public-skills && git checkout -b feature/jujutsu
Switched to a new branch 'feature/jujutsu'
Now add the files and commit.
Command:
cd ~/projects/public-skills && git add skills/jujutsu/ && git commit -m "feat: add jujutsu skill for jj-enabled projects"
[feature/jujutsu 09f7788] feat: add jujutsu skill for jj-enabled projects
4 files changed, 465 insertions(+)
create mode 100644 skills/jujutsu/SKILL.md
create mode 100644 skills/jujutsu/references/commands.md
create mode 100644 skills/jujutsu/references/pitfalls.md
create mode 100644 skills/jujutsu/references/revsets.md
Now push the branch and create a PR.
Command:
cd ~/projects/public-skills && git push -u origin feature/jujutsu
remote:
remote: Create a pull request for 'feature/jujutsu' on GitHub by visiting:
remote: https://github.com/lambda610/skills/pull/new/feature/jujutsu
remote:
To github.com:lambda610/skills.git
* [new branch] feature/jujutsu -> feature/jujutsu
branch 'feature/jujutsu' set up to track 'origin/feature/jujutsu'.
Now create the PR using gh CLI.
Command:
cd ~/projects/public-skills && gh pr create --title "feat: add jujutsu skill" --body "## 概述
为 jj 项目创建 Jujutsu 使用指南 skill。
## 文件结构
\`\`\`
jujutsu/
├── SKILL.md # 触发 + 心智模型 + 常用命令
└── references/
├── commands.md # git ↔ jj 对照表
├── pitfalls.md # 常见错误
└── revsets.md # Revset 查询语法
\`\`\`
## 核心内容
- 明确何时使用(仅 jj 项目)
- 心智模型差异(vs Git)
- 常用命令速查
- 常见工作流示例
- 错误检查清单
## 链接
https://github.com/lambda610/skills/pull/new/feature/jujutsu"
https://github.com/lambda610/skills/pull/7
Done! PR created successfully.
Yelo 让我认真阅读官方文档来更正 skill 中的错误。我需要逐个阅读这些文档并记录笔记,然后更新 skill 内容。
让我开始逐个阅读这些文档。
Command:
curl -s "https://www.jj-vcs.dev/latest/working-copy/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
Great, I'm getting good info. Let me continue reading more pages.
Command:
curl -s "https://www.jj-vcs.dev/latest/bookmarks/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
Good information. Let me continue with more pages.
Command:
curl -s "https://www.jj-vcs.dev/latest/conflicts/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -300
[CONDENSED]
This is very helpful. Let me continue with more pages to get a comprehensive understanding.
Command:
curl -s "https://www.jj-vcs.dev/latest/git-comparison/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -500
[CONDENSED]
This is extremely helpful. Let me continue with more documentation pages.
Command:
curl -s "https://www.jj-vcs.dev/latest/git-command-table/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -600
[CONDENSED]
This is extremely helpful. Let me continue with more pages. I should note:
jj new- Creates a new change on top (can take a revision argument)jj co- Actually, looking at this table, there's no directjj cocommand, you usejj new <bookmark>to create a new change on top of a bookmarkjj rebase -bvs-s- The table clarifies this well- No
jj checkout- usejj neworjj edit - No
git stashequivalent - usejj new @- - The command table shows a lot of useful comparisons
Let me continue reading more docs to get more details.
Command:
curl -s "https://www.jj-vcs.dev/latest/revsets/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
This is excellent. Let me continue reading a few more pages to get a complete picture.
Command:
curl -s "https://www.jj-vcs.dev/latest/git-experts/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -300
[CONDENSED]
This is extremely helpful. Let me now make a comprehensive note and update the skill with accurate information. Let me also check a few more docs like glossary and FAQ.
Command:
curl -s "https://www.jj-vcs.dev/latest/FAQ/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -200
(no output)
Let me try to get the FAQ page with a different approach.
Command:
curl -s "https://www.jj-vcs.dev/latest/FAQ/" -H "User-Agent: Mozilla/5.0" | grep -oP '(?<=<h2>)[^<]+' | head -20
(no output)
Let me now take notes and update the skill. I've gathered a lot of useful information from the docs. Let me summarize the key findings and fix the skill.
File: ~/projects/public-skills/skills/jujutsu/SKILL.md
Content (4097 chars):
---
name: jujutsu
description: Use Jujutsu (jj) for version control in jj-enabled projects. Applies when the project uses jj (has .jj/ directory, README specifies jj, or user requests jj).
---
# Jujutsu 使用指南
Jujutsu (jj) 是新一代分布式版本控制工具,兼容 Git 仓库但用法有根本差异。
## 何时使用
**仅在明确使用 jj 的项目中使用此 skill。** 判断方法:
- 存在 `.jj/` 目录
- 项目 README 明确要求用 jj
- 用户明确指定用 jj
对于普通 Git 项目,使用标准的 Git 工具。
## 心智模型(与 Git 的根本差异)
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 是可编辑的 change |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| `git stash` 暂存 | 用 `jj new @-` 或 `jj shelf` |
| 冲突必须立即解决 | jj 冲突可延迟处理 |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,类似 Git branch 但有 tracked 概念
5. **Revsets** — 强大的查询语法,能表达复杂条件
6. **无 checkout** — 用 `jj new` 或 `jj edit` 切换
## 常用命令速查
```bash
# 查看状态
jj st # 当前变更(相当于 git status)
jj log # 历史
jj log --graph # 图形化历史
# 操作变更(无需 add)
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(自动包含所有修改)
jj squash # 合并到父提交(类似 git commit --amend)
jj restore <path> # 撤销文件修改
# 注意:没有 jj co 或 jj checkout!
# 切换到某 bookmark:用 jj new <bookmark>
# 编辑某 commit:用 jj edit <revision>
# Bookmarks(类似 branch,但不同)
jj bookmark list # 列出 bookmarks
jj bookmark create <name> -r <revision> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <revision> # 移动 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动 bookmark 及其指向的 commit
jj rebase -s <commit> -o <dest> # 移动 commit 及其后代
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
```
## 常见工作流
### 日常提交
```bash
# 1. 查看变更
jj st
jj diff
# 2. 提交(无需 add!)
jj commit -m "feat: add new feature"
# 3. 查看历史
jj log
```
### 修改历史提交
```bash
# 修改当前提交的描述
jj describe -m "new message"
# 把当前变更合并到上一个提交
jj squash
# 把变更 squash 到指定提交
jj squash --into <commit>
```
### 创建新分支(在某 bookmark 上开始工作)
```bash
# 相当于 git checkout -b topic main
jj new main
jj bookmark create topic
# 或者一步到位:
jj new main -b topic
```
### 变基
```bash
# 移动 bookmark A 到 B 上(类似 git rebase)
jj rebase -b A -o B
# 移动 commit 及其后代到新基础
jj rebase -s <commit> -o <dest>
```
### 处理冲突
```bash
# 1. 冲突不会中断操作,会创建 conflicted change
# 2. 创建新 commit 来解决冲突
jj new <conflicted-commit>
# 3. 解决文件中的冲突标记
# 编辑文件...
# 4. 标记已解决
jj resolve <file>
# 5. squash 到原提交
jj squash
```
### 临时保存当前工作
```bash
# 相当于 git stash:创建兄弟 commit
jj new @-
# 恢复:用 jj edit <commit> 回到之前的 commit
```
### 与远程同步
```bash
# 拉取
jj git fetch
# 如果有远程更新,先 fetch
jj git fetch
# 推送
jj git push
```
## 关键命令对照
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | |
| `git diff` | `jj diff` | |
| `git add` | ❌ 不需要 | jj 自动追踪 |
| `git commit` | `jj commit -m "msg"` | |
| `git commit --amend` | `jj squash` | |
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | |
| `git branch` | `jj bookmark list` | |
| `git merge A` | `jj new @ A` | |
| `git rebase B A` | `jj rebase -b A -o B` | |
| `git stash` | `jj new @-` | |
| `git reset --hard` | `jj abandon` | |
| `git reset --soft HEAD~` | `jj squash --from @-` | |
**注意**:jj 没有 `jj co` 或 `jj checkout` 命令!
## 注意事项
1. **不要用 `git add`** — jj 自动追踪
2. **不要用 `jj co`** — 用 `jj new` 或 `jj edit`
3. **`jj commit` 自动包含所有修改** — 不需要 `-a`
4. **冲突不阻塞** — 可以继续工作,稍后再解决
5. **`jj new` 创建的是 change** — 是可编辑的空 commit
6. **Bookmarks 有 tracked 概念** — 类似 Git 的 upstream
## Revset 快速参考
```bash
# 常用符号
@ # 当前 working-copy commit
@- # 父提交
root() # 根提交
bookmarks() # 所有 bookmark
# 运算符
:: # 祖先(包含自己)
.. # 不包含祖先
~ # 差集
| # 并集
& # 交集
# 示例
jj log -r ::@ # 当前 commit 的祖先链
jj log -r 'all()' # 所有可见 commit
jj log -r main.. # main 分支后的 commit
```
## 获取帮助
```bash
jj help
jj help <subcommand>
```
Successfully wrote 4097 bytes to ~/projects/public-skills/skills/jujutsu/SKILL.md
Now let me update the references files as well.
File: ~/projects/public-skills/skills/jujutsu/references/commands.md
Content (3216 chars):
# 命令对照表(带解释)
> 基于官方文档:https://www.jj-vcs.dev/latest/git-command-table/
## 基础操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | 查看当前工作状态 |
| `git diff` | `jj diff` | 查看未提交的修改 |
| `git diff HEAD` | `jj diff` | 同上,jj 默认比较 HEAD |
| `git diff <A>..<B>` | `jj diff -r A..B` | 比较两个提交 |
| `git add` | ❌ 不需要 | jj 自动追踪所有修改 |
| `git commit` | `jj commit -m "msg"` | 提交当前所有变更 |
| `git commit -a` | `jj commit` | 同上,jj 不需要 -a |
| `git commit --amend` | `jj squash` | 把当前变更合并到父提交 |
| `git restore <file>` | `jj restore <file>` | 撤销文件修改 |
| `git checkout -- <file>` | `jj restore <file>` | 同上 |
## 历史查看
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git log` | `jj log` | 查看历史 |
| `git log --oneline` | `jj log -r ::@` | 简洁格式 |
| `git log --graph` | `jj log --graph` | 图形化 |
| `git log --all` | `jj log -r 'all()'` | 查看所有 |
| `git show <rev>` | `jj show <rev>` | 查看提交详情 |
| `git blame <file>` | `jj file annotate <file>` | 文件注解 |
## ⚠️ 分支操作(关键区别!)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并切换 |
| `git branch` | `jj bookmark list` | 列出 |
| `git branch <name>` | `jj bookmark create <name>` | 创建 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动 |
**关键点**:
- jj 没有 `jj co` 或 `jj checkout` 命令!
- 用 `jj new <bookmark>` 创建新 change 并切换到它
- 用 `jj edit <revision>` 在 working copy 中编辑某 commit
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ A` | 合并(创建新 change) |
| `git rebase <B> <A>` | `jj rebase -b A -o B` | 移动 bookmark |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 移动 commit 及后代 |
**关键区别**:
- `-b` = 移动 bookmark 指向的 commit
- `-s` = 移动指定 commit 及其所有后代
## 远程操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git fetch` | `jj git fetch` | 拉取 |
| `git pull` | `jj git fetch` (+ `jj new`) | |
| `git push` | `jj git push` | 推送 |
| `git push <remote> <branch>` | `jj git push --bookmark <name>` | |
| `git remote add` | `jj git remote add` | |
## 暂存与撤销
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git stash` | `jj new @-` | 暂存到兄弟 commit |
| `git stash pop` | `jj edit <commit>` | 恢复 |
| `git reset --hard` | `jj abandon` | 放弃当前 change |
| `git reset --soft HEAD~` | `jj squash --from @-` | 保留修改 |
| `git cherry-pick <rev>` | `jj duplicate <rev> -o @` | 复制提交 |
## 撤销操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git reflog` | `jj op log` | 查看操作日志 |
| `git reset --hard <ref>` | `jj undo` | 撤销上一次操作 |
**jj 的 `jj undo` 更强大** — 可以撤销几乎任何操作!
## 文件操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git ls-files` | `jj file list` | 列出文件 |
| `git rm <file>` | `jj file delete <file>` | 删除 |
| `git rm --cached <file>` | `jj file untrack <file>` | 取消跟踪(需匹配 ignore pattern) |
| `git rev-parse --show-toplevel` | `jj workspace root` | 仓库根目录 |
## 高级操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git add -p` | `jj split` | 交互式拆分 |
| `git rebase -i` | `jj rebase -r` | 交互式变基 |
| | `jj absorb` | 自动吸收修改到之前的 commit |
| | `jj diffedit` | 交互式编辑某 commit 的 diff |
| | `jj describe` | 修改 commit 信息 |
Successfully wrote 3216 bytes to ~/projects/public-skills/skills/jujutsu/references/commands.md
Now let me update the pitfalls.md file with corrected information.
File: ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
Content (2319 chars):
# 常见错误与陷阱
> 基于官方文档,Agent 容易犯的错误。
## 🔴 严重错误
### 用 `git add`
**错误**:想暂存文件时用 `git add`
**问题**:jj 没有暂存区概念,`git add` 不会生效
**正确做法**:
```bash
# jj 自动追踪所有修改,直接提交即可
jj commit -m "message"
# 如果只想提交部分文件,用 jj split
jj split file1 file2
```
### 用 `jj co` 或 `jj checkout` 切换
**错误**:用 `jj co <bookmark>` 或 `jj checkout`
**问题**:jj 根本没有这两个命令!
**正确做法**:
```bash
# 创建新 change 在 bookmark 上(相当于 checkout -b)
jj new main
# 创建新 change 并设置 bookmark
jj new main -b myfeature
# 编辑现有 commit
jj edit <revision>
```
### 用 `git stash` 暂存
**错误**:用 `git stash`
**问题**:jj 没有 stash,用 `jj new @-` 创建兄弟 commit
**正确做法**:
```bash
# 临时保存当前工作(创建兄弟 commit)
jj new @-
# 恢复:用 jj edit 回到原 commit
jj edit <原commit>
```
### 用 `git merge`
**错误**:用 `jj merge`
**问题**:jj 没有 merge 命令
**正确做法**:
```bash
# 合并 A 到当前 commit
jj new @ A
```
## 🟠 易错操作
### 混淆 `-b` 和 `-s` 在 rebase
**误解**:`-b` 移动单个 commit
**正确**:
- `-b <bookmark>`:移动 bookmark 指向的 commit(不包含后代)
- `-s <commit>`:移动 commit 及其所有后代
```bash
# 错误
jj rebase -b A -o B # 移动 A(不含后代)
# 正确(移动 A 及其后代)
jj rebase -s A -o B
```
### `jj new` 不带参数
**误解**:`jj new` 等于 `git checkout -b`
**正确**:`jj new` 基于当前 `@` 创建新 change,不带 bookmark 名
```bash
# 创建新 change(无 bookmark)
jj new
# 创建并设置 bookmark
jj new -b <bookmark>
# 基于某提交创建
jj new <revision>
```
### 冲突后不知如何继续
**误解**:遇到冲突必须立即解决
**正确**:jj 允许先继续工作,稍后再解决
```bash
# 冲突后,jj 会创建 conflicted change
# 可以继续创建新 commit
jj new
# 之后回到冲突 commit 解决
jj new <conflicted-commit>
# 解决文件中的冲突
jj resolve <file>
jj squash
```
### 用 `jj file untrack` 但不设置 ignore
**错误**:直接 `jj file untrack`
**问题**:文件必须匹配 ignore pattern 才能 untrack
**正确做法**:
```bash
# 1. 先添加到 .gitignore
echo "file.txt" >> .gitignore
# 2. 再 untrack
jj file untrack file.txt
```
## 🟡 小问题
### 忘记 `-m` 参数
**问题**:`jj commit` 不带 `-m` 会打开编辑器
**建议**:习惯用 `jj commit -m "message"`
### 混淆 bookmarks 和 changes
- **Bookmark**:类似 Git branch,是指向提交的指针
- **Change**:jj 核心概念,是可编辑的提交
- **Working-copy commit**:当前工作目录的 commit(@ 符号)
### 在 Git 项目中直接用 `git init`
**问题**:应该用 `jj git init`
**正确**:
```bash
jj git init
# 或
jj git clone <url>
```
## 检查清单
操作前快速检查:
- [ ] 不要用 `git add`
- [ ] 不要用 `jj co` 或 `jj checkout`
- [ ] 用 `jj commit` 而不是 `git commit`
- [ ] 用 `jj bookmark` 而不是 `git branch`
- [ ] 用 `jj new @ A` 而不是 `git merge`
- [ ] 用 `jj rebase -b` 或 `-s` 变基
- [ ] 用 `jj new @-` 暂存而不是 `git stash`
Successfully wrote 2319 bytes to ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
Now let me update the revsets.md file with the accurate information I gathered from the official docs.
File: ~/projects/public-skills/skills/jujutsu/references/revsets.md
Content (2491 chars):
# Revset 查询语法
> 基于官方文档:https://www.jj-vcs.dev/latest/revsets/
Revset 是 jj 强大的查询语法,能精确定位提交。
## 基本语法
```bash
jj log -r <revset>
```
## 常用符号
| 符号 | 含义 |
|------|------|
| `@` | 当前 working-copy commit |
| `@-` | 当前 commit 的父提交 |
| `@--` | 祖父提交 |
| `main` | bookmark 名为 main 的提交 |
| `HEAD` | HEAD 指向的提交 |
| `root()` | 仓库根提交(虚拟 commit,hash 全为 0) |
## 运算符
| 运算符 | 含义 | 示例 |
|--------|------|------|
| `::` | 祖先范围(包含自己) | `main::` = main 的所有后代 |
| `..` | 不包含祖先 | `main..main~5` |
| `|` | 并集 | `main \| feature` |
| `&` | 交集 | `main & @` |
| `~` | 差集 | `@ ~ main` |
| `-` | 父母(单数) | `@-` = 父提交 |
| `+` | 子孙(单数) | |
## 范围运算符
| 运算符 | 含义 |
|--------|------|
| `x::y` | x 到 y 之间的后代(包含 x 和 y) |
| `x..y` | x 到 y 之间的祖先(不包含 x 的祖先) |
| `::x` | x 的所有祖先 |
| `x::` | x 的所有后代 |
**注意**:`..` 在左边时不分配(不同于 `|`):
- `(A | B)..` = `A.. & B..`(交集)
- `A.. | B..` = 并集
## 函数
| 函数 | 用法 | 说明 |
|------|------|------|
| `all()` | `all()` | 所有可见 commit |
| `none()` | `none()` | 空集 |
| `bookmarks()` | `bookmarks()` | 所有本地 bookmark |
| `bookmarks(pattern)` | `bookmarks("main")` | 匹配 pattern 的 bookmark |
| `remote_bookmarks()` | `remote_bookmarks()` | 所有远程 bookmark |
| `visible_heads()` | `visible_heads()` | 所有可见 head |
| `parents(x)` | `parents(@)` | x 的父母 |
| `children(x)` | `children(@)` | x 的子孙 |
| `ancestors(x)` | `ancestors(@)` | x 的祖先 |
| `descendants(x)` | `descendants(@)` | x 的后代 |
| `first_parent(x)` | `first_parent(@)` | 只取第一个父母 |
| `latest(x)` | `latest(@, 5)` | 最近 N 个 |
| `merges()` | `merges()` | 合并提交 |
| `file(path)` | `file("src/main.rs")` | 包含某文件的 commit |
| `author(name)` | `author("yelo")` | 作者匹配 |
| `description(text)` | `description("feat")` | 描述包含 |
| `date(expr)` | `date(2024-01-01)` | 日期 |
## 常见用法
```bash
# 当前分支的历史
jj log -r ::@
# 所有未推送的提交
jj log -r '@..@|bookmarks(@)..'
# 某个 bookmark 的历史
jj log -r main::main
# 最近 5 个提交
jj log -r latest(@, 5)
# 包含某个文件的提交
jj log -r 'file(path/to/file)'
# 在某日期之后的提交
jj log -r 'date(2024-01-01)..'
# 作者包含某字符串的提交
jj log -r 'author(yelo)'
# 合并提交
jj log -r 'merges()'
# 空提交(无文件变更)
jj log -r 'empty()'
# 可变 commits(本地修改过的)
jj log -r 'mutable()'
```
## 快捷方式
| 快捷 | 展开 |
|-------|------|
| `@~n` | `@-n`,第 n 个祖先 |
| `@^` | `@-`,父提交 |
| `main~3` | main 的第 3 个祖先 |
## 示例
```bash
# 查看当前 commit 的祖先链
jj log -r ::@
# 查看 feature 分支独有的提交
jj log -r 'feature - main'
# 查看最近一周的提交
jj log -r 'date(-7d)..'
# 查看两个 bookmark 之间的差异
jj diff -r main..feature
# 查看某个人的所有提交
jj log -r 'author(yelo)'
# 查看所有 bookmark 的最新位置
jj log -r 'bookmarks()'
```
Successfully wrote 2491 bytes to ~/projects/public-skills/skills/jujutsu/references/revsets.md
Now let me commit these changes to the feature branch.
Command:
cd ~/projects/public-skills && git status
On branch feature/jujutsu
Your branch is up to date with 'origin/feature/jujutsu'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: skills/jujutsu/SKILL.md
modified: skills/jujutsu/references/commands.md
modified: skills/jujutsu/references/pitfalls.md
modified: skills/jujutsu/references/revsets.md
no changes added to commit (use "git add" and/or "git commit -a")
Now let me commit and push these updates.
Command:
cd ~/projects/public-skills && git add -A && git commit -m "fix: correct jujutsu commands based on official docs"
[feature/jujutsu 65287b5] fix: correct jujutsu commands based on official docs
4 files changed, 313 insertions(+), 155 deletions(-)
Now push the changes.
Command:
cd ~/projects/public-skills && git push
To github.com:lambda610/skills.git
09f7788..65287b5 feature/jujutsu -> feature/jujutsu
Done! The PR has been updated. Let me give Yelo a summary.
Yelo 问我是否读完了所有文档。让我回顾一下我读的:
-
❓ https://www.jj-vcs.dev/latest/operation-log/ - 没单独读,但在其他地方有涉及
-
❓ https://www.jj-vcs.dev/latest/guides/cli-revision-options/ - 没读
-
❓ https://www.jj-vcs.dev/latest/guides/multiple-remotes/ - 没读
-
❓ https://www.jj-vcs.dev/latest/FAQ/ - 尝试读但没成功
我需要诚实地告诉 Yelo,我只读了一部分,还有几个重要的部分没有覆盖到。
Yelo wants me to read all the remaining documents. Let me continue reading the ones I haven't read yet.
Command:
curl -s "https://www.jj-vcs.dev/latest/operation-log/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -300
[CONDENSED]
Let me continue with the other documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/glossary/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
This glossary is very helpful! Let me continue with the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/git-compatibility/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
This is great information about Git compatibility. Let me continue with the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/config/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -400
[CONDENSED]
Let me continue reading the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/filesets/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -200
[CONDENSED]
Let me continue with the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/guides/cli-revision-options/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -200
[CONDENSED]
Let me continue with the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/guides/divergence/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -200
[CONDENSED]
Let me continue reading the remaining documents.
Command:
curl -s "https://www.jj-vcs.dev/latest/guides/multiple-remotes/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -200
[CONDENSED]
Now let me read the templates doc and check if there's an FAQ.
Command:
curl -s "https://www.jj-vcs.dev/latest/templates/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | head -300
[CONDENSED]
Now I have a comprehensive understanding of Jujutsu. Let me now update the skill with the new information I've learned.
Key things I learned:
- No jj co or jj checkout - Must use jj new or jj edit
- Colocated workspaces - jj and git can be used side by side
- Operation log - More powerful than git reflog
- Divergent changes - Multiple visible commits with same change ID
- Multiple remotes - Different workflows for forks vs integration
- Filesets - Similar to revsets but for files
- Templates - Customizing output
- Config - Extensive configuration options
Let me update the skill with this new knowledge.
Yelo 说要把新读的加进去,还说我前面读的内容可能也有没加的。让我检查一下 skill 里已经有什么,然后补充缺失的内容。
现在 skill 里的内容:
- SKILL.md: 基础概念、心智模型、常用命令、工作流、命令对照
- references/commands.md: 命令对照表
- references/pitfalls.md: 常见错误
- references/revsets.md: Revset 查询
可能缺失的:
- Colocated workspaces - 并存工作区
- Multiple remotes - 多远程
- Divergent changes - 分叉变化
- Operation log - 操作日志(已有简单提及)
- Filesets - 文件集
- Templates - 模板
- Conflict 详细处理
- Bookmark tracking 详细说明
让我补充这些内容。
Command:
ls -la ~/projects/public-skills/skills/jujutsu/
total 20
drwxrwxr-x 3 user user 4096 Mar 6 00:23 .
drwxrwxr-x 7 user user 4096 Mar 6 00:22 ..
drwxrwxr-x 2 user user 4096 Mar 6 00:24 references
-rw-rw-r-- 1 user user 5593 Mar 6 01:10 SKILL.md
现在我需要补充以下内容:
- Colocated workspaces(新增)
- Multiple remotes(新增)
- Divergent changes(新增)
- Conflict 详细处理
- Bookmark tracking 详细
- Filesets(新增)
- Operation log 详细
让我更新 SKILL.md 并创建新的 reference 文件。
File: ~/projects/public-skills/skills/jujutsu/SKILL.md
Content (5019 chars):
---
name: jujutsu
description: Use Jujutsu (jj) for version control in jj-enabled projects. Applies when the project uses jj (has .jj/ directory, README specifies jj, or user requests jj).
---
# Jujutsu 使用指南
Jujutsu (jj) 是新一代分布式版本控制工具,兼容 Git 仓库但用法有根本差异。
## 何时使用
**仅在明确使用 jj 的项目中使用此 skill。** 判断方法:
- 存在 `.jj/` 目录
- 项目 README 明确要求用 jj
- 用户明确指定用 jj
对于普通 Git 项目,使用标准的 Git 工具。
## 心智模型(与 Git 的根本差异)
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 是可编辑的 change |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| `git stash` 暂存 | 用 `jj new @-` 或 `jj shelf` |
| 冲突必须立即解决 | jj 冲突可延迟处理 |
| checkout 切换分支 | 用 `jj new` 或 `jj edit`(无 checkout) |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,类似 Git branch 但有 tracked 概念
5. **Revsets** — 强大的查询语法,能表达复杂条件
6. **无 checkout** — 用 `jj new` 或 `jj edit` 切换
7. **冲突不阻塞** — 冲突记录在 commit 中,可稍后解决
## 核心概念
### Change vs Commit
- **Commit**:文件的快照 + 元数据(作者、日期、父提交)
- **Change**:commit 的演化历史,用 change ID 标识(类似 Gerrit 的 Change-Id)
- **Working-copy commit**:当前工作目录对应的 commit(@ 符号)
### Change ID vs Commit ID
- **Change ID**:jj 特有,16 字节随机生成,格式如 `kntqzsqt`,会保持不变
- **Commit ID**:Git 兼容的提交哈希,会随内容变化
### Bookmark vs Branch
- **Bookmark**:指向 commit 的命名指针,类似 Git branch
- **无"当前 bookmark"** — jj 没有活跃分支的概念
- **Tracked bookmark**:跟踪远程同名 bookmark
### Colocated Workspaces
jj 和 git 可共存于同一目录:
- `.jj/` + `.git/` 共存
- jj 和 git 命令可混用
- jj 自动 import/export 到 git
## 常用命令速查
```bash
# 查看状态
jj st # 当前变更(相当于 git status)
jj log # 历史
jj log --graph # 图形化历史
# 操作变更(无需 add)
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(自动包含所有修改)
jj squash # 合并到父提交(类似 git commit --amend)
jj restore <path> # 撤销文件修改
# 注意:没有 jj co 或 jj checkout!
# 切换到某 bookmark:用 jj new <bookmark>
# 编辑某 commit:用 jj edit <revision>
# Bookmarks(类似 branch,但不同)
jj bookmark list # 列出 bookmarks
jj bookmark create <name> -r <revision> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <revision> # 移动 bookmark
jj bookmark track <name> --remote=<remote> # 跟踪远程 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动 bookmark 及其指向的 commit
jj rebase -s <commit> -o <dest> # 移动 commit 及其后代
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
# 多远程
jj config set --repo git.fetch '["upstream", "origin"]'
jj bookmark track main # 跟踪远程 bookmark
```
## 常见工作流
### 日常提交
```bash
# 1. 查看变更
jj st
jj diff
# 2. 提交(无需 add!)
jj commit -m "feat: add new feature"
# 3. 查看历史
jj log
```
### 修改历史提交
```bash
# 修改当前提交的描述
jj describe -m "new message"
# 把当前变更合并到上一个提交
jj squash
# 把变更 squash 到指定提交
jj squash --into <commit>
```
### 创建新分支
```bash
# 相当于 git checkout -b topic main
jj new main
jj bookmark create topic
# 或者一步到位:
jj new main -b topic
```
### 变基
```bash
# 移动 bookmark A 到 B 上(类似 git rebase)
jj rebase -b A -o B
# 移动 commit 及其后代到新基础
jj rebase -s <commit> -o <dest>
```
### 处理冲突
```bash
# 1. 冲突不会中断操作,会创建 conflicted change
# 2. 创建新 commit 来解决冲突
jj new <conflicted-commit>
# 3. 解决文件中的冲突标记
# 编辑文件...
# 4. 标记已解决
jj resolve <file>
# 5. squash 到原提交
jj squash
```
### 临时保存当前工作
```bash
# 相当于 git stash:创建兄弟 commit
jj new @-
# 恢复:用 jj edit <commit> 回到之前的 commit
```
### Divergent Changes(分叉变化)
当同一 change ID 有多个可见 commit 时:
```bash
# 查看
jj log # 显示 divergent 标记
# 解决策略
jj abandon <unwanted-commit-id> # 放弃一个
jj metaedit --update-change-id <commit-id> # 生成新 change ID
jj squash --from <source> --into <target> # 合并两个
```
## 关键命令对照
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | |
| `git diff` | `jj diff` | |
| `git add` | ❌ 不需要 | jj 自动追踪 |
| `git commit` | `jj commit -m "msg"` | |
| `git commit --amend` | `jj squash` | |
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | |
| `git branch` | `jj bookmark list` | |
| `git merge A` | `jj new @ A` | |
| `git rebase B A` | `jj rebase -b A -o B` | |
| `git stash` | `jj new @-` | |
| `git reset --hard` | `jj abandon` | |
| `git reflog` | `jj op log` | |
## 注意事项
1. **不要用 `git add`** — jj 自动追踪
2. **不要用 `jj co`** — 用 `jj new` 或 `jj edit`
3. **`jj commit` 自动包含所有修改** — 不需要 `-a`
4. **冲突不阻塞** — 可以继续工作,稍后再解决
5. **`jj new` 创建的是 change** — 是可编辑的空 commit
6. **Bookmarks 有 tracked 概念** — 类似 Git 的 upstream
## Revset 快速参考
```bash
# 常用符号
@ # 当前 working-copy commit
@- # 父提交
root() # 根提交
bookmarks() # 所有 bookmark
# 运算符
:: # 祖先(包含自己)
.. # 不包含祖先
~ # 差集
| # 并集
& # 交集
# 示例
jj log -r ::@ # 当前 commit 的祖先链
jj log -r 'all()' # 所有可见 commit
jj log -r main.. # main 分支后的 commit
```
## 获取帮助
```bash
jj help
jj help <subcommand>
```
更多内容:见 `references/` 目录
Successfully wrote 5019 bytes to ~/projects/public-skills/skills/jujutsu/SKILL.md
现在让我创建/更新 references 目录的文件。
File: ~/projects/public-skills/skills/jujutsu/references/commands.md
Content (3351 chars):
# 命令对照表(带解释)
> 基于官方文档:https://www.jj-vcs.dev/latest/git-command-table/
## 基础操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | 查看当前工作状态 |
| `git diff` | `jj diff` | 查看未提交的修改 |
| `git diff HEAD` | `jj diff` | 同上,jj 默认比较 HEAD |
| `git diff <A>..<B>` | `jj diff -r A..B` | 比较两个提交 |
| `git add` | ❌ 不需要 | jj 自动追踪所有修改 |
| `git commit` | `jj commit -m "msg"` | 提交当前所有变更 |
| `git commit -a` | `jj commit` | 同上,jj 不需要 -a |
| `git commit --amend` | `jj squash` | 把当前变更合并到父提交 |
| `git restore <file>` | `jj restore <file>` | 撤销文件修改 |
| `git checkout -- <file>` | `jj restore <file>` | 同上 |
## 历史查看
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git log` | `jj log` | 查看历史 |
| `git log --oneline` | `jj log -r ::@` | 简洁格式 |
| `git log --graph` | `jj log --graph` | 图形化 |
| `git log --all` | `jj log -r 'all()'` | 查看所有 |
| `git show <rev>` | `jj show <rev>` | 查看提交详情 |
| `git blame <file>` | `jj file annotate <file>` | 文件注解 |
## ⚠️ 分支操作(关键区别!)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并切换 |
| `git branch` | `jj bookmark list` | 列出 |
| `git branch <name>` | `jj bookmark create <name>` | 创建 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动 |
**关键点**:
- jj 没有 `jj co` 或 `jj checkout` 命令!
- 用 `jj new <bookmark>` 创建新 change 并切换到它
- 用 `jj edit <revision>` 在 working copy 中编辑某 commit
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ A` | 合并(创建新 change) |
| `git rebase <B> <A>` | `jj rebase -b A -o B` | 移动 bookmark |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 移动 commit 及后代 |
**关键区别**:
- `-b` = 移动 bookmark 指向的 commit(不包含后代)
- `-s` = 移动指定 commit 及其所有后代
## 远程操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git fetch` | `jj git fetch` | 拉取 |
| `git pull` | `jj git fetch` (+ `jj new`) | |
| `git push` | `jj git push` | 推送 |
| `git push <remote> <branch>` | `jj git push --bookmark <name>` | |
| `git remote add` | `jj git remote add` | |
| `git branch -u <remote>/<branch>` | `jj bookmark track <name> --remote=<remote>` | 跟踪远程 |
## 暂存与撤销
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git stash` | `jj new @-` | 暂存到兄弟 commit |
| `git stash pop` | `jj edit <commit>` | 恢复 |
| `git reset --hard` | `jj abandon` | 放弃当前 change |
| `git reset --soft HEAD~` | `jj squash --from @-` | 保留修改 |
| `git cherry-pick <rev>` | `jj duplicate <rev> -o @` | 复制提交 |
## 撤销操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git reflog` | `jj op log` | 查看操作日志 |
| `git reset --hard <ref>` | `jj undo` | 撤销上一次操作 |
**jj 的 `jj undo` 更强大** — 可以撤销几乎任何操作!
## 文件操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git ls-files` | `jj file list` | 列出文件 |
| `git rm <file>` | `jj file delete <file>` | 删除 |
| `git rm --cached <file>` | `jj file untrack <file>` | 取消跟踪(需匹配 ignore pattern) |
| `git rev-parse --show-toplevel` | `jj workspace root` | 仓库根目录 |
## 高级操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git add -p` | `jj split` | 交互式拆分 |
| `git rebase -i` | `jj rebase -r` | 交互式变基 |
| | `jj absorb` | 自动吸收修改到之前的 commit |
| | `jj diffedit` | 交互式编辑某 commit 的 diff |
| | `jj describe` | 修改 commit 信息 |
| | `jj evolog` | 查看 change 的演化历史 |
Successfully wrote 3351 bytes to ~/projects/public-skills/skills/jujutsu/references/commands.md
现在让我更新 pitfalls.md:
File: ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
Content (2867 chars):
# 常见错误与陷阱
> 基于官方文档,Agent 容易犯的错误。
## 🔴 严重错误
### 用 `git add`
**错误**:想暂存文件时用 `git add`
**问题**:jj 没有暂存区概念,`git add` 不会生效
**正确做法**:
```bash
# jj 自动追踪所有修改,直接提交即可
jj commit -m "message"
# 如果只想提交部分文件,用 jj split
jj split file1 file2
```
### 用 `jj co` 或 `jj checkout` 切换
**错误**:用 `jj co <bookmark>` 或 `jj checkout`
**问题**:jj 根本没有这两个命令!
**正确做法**:
```bash
# 创建新 change 在 bookmark 上(相当于 checkout -b)
jj new main
# 创建新 change 并设置 bookmark
jj new main -b myfeature
# 编辑现有 commit
jj edit <revision>
```
### 用 `git stash` 暂存
**错误**:用 `git stash`
**问题**:jj 没有 stash,用 `jj new @-` 创建兄弟 commit
**正确做法**:
```bash
# 临时保存当前工作(创建兄弟 commit)
jj new @-
# 恢复:用 jj edit 回到原 commit
jj edit <原commit>
```
### 用 `git merge`
**错误**:用 `jj merge`
**问题**:jj 没有 merge 命令
**正确做法**:
```bash
# 合并 A 到当前 commit
jj new @ A
```
## 🟠 易错操作
### 混淆 `-b` 和 `-s` 在 rebase
**误解**:`-b` 移动单个 commit
**正确**:
- `-b <bookmark>`:移动 bookmark 指向的 commit(不包含后代)
- `-s <commit>`:移动 commit 及其所有后代
```bash
# 错误
jj rebase -b A -o B # 移动 A(不含后代)
# 正确(移动 A 及其后代)
jj rebase -s A -o B
```
### `jj new` 不带参数
**误解**:`jj new` 等于 `git checkout -b`
**正确**:`jj new` 基于当前 `@` 创建新 change,不带 bookmark 名
```bash
# 创建新 change(无 bookmark)
jj new
# 创建并设置 bookmark
jj new -b <bookmark>
# 基于某提交创建
jj new <revision>
```
### 冲突后不知如何继续
**误解**:遇到冲突必须立即解决
**正确**:jj 允许先继续工作,稍后再解决
```bash
# 冲突后,jj 会创建 conflicted change
# 可以继续创建新 commit
jj new
# 之后回到冲突 commit 解决
jj new <conflicted-commit>
# 解决文件中的冲突
jj resolve <file>
jj squash
```
### 用 `jj file untrack` 但不设置 ignore
**错误**:直接 `jj file untrack`
**问题**:文件必须匹配 ignore pattern 才能 untrack
**正确做法**:
```bash
# 1. 先添加到 .gitignore
echo "file.txt" >> .gitignore
# 2. 再 untrack
jj file untrack file.txt
```
### 混淆 bookmarks 和 changes
**误解**:bookmark 就是 branch
**正确**:
- **Bookmark**:类似 Git branch,是指向提交的指针
- **Change**:jj 核心概念,是可编辑的提交
- **Working-copy commit**:当前工作目录的 commit(@ 符号)
- **无"当前 bookmark"** — jj 没有活跃分支的概念
### 忽略 divergent changes
**误解**:只要用 change ID 就不会有歧义
**正确**:如果 change ID 分叉了,需要用 commit ID 或带偏移的 change ID
```bash
# 分叉的 change ID
jj log # 显示为 xyz/0, xyz/1
# 用 commit ID 指定
jj edit <commit-id>
# 或用带偏移的 change ID
jj edit xyz/0
```
## 🟡 小问题
### 忘记 `-m` 参数
**问题**:`jj commit` 不带 `-m` 会打开编辑器
**建议**:习惯用 `jj commit -m "message"`
### 在 Git 项目中直接用 `git init`
**问题**:应该用 `jj git init`
**正确**:
```bash
jj git init
# 或
jj git clone <url>
```
### 混淆 tracked vs untracked bookmarks
**误解**:fetch 后自动跟踪
**正确**:
```bash
# 默认只跟踪 origin 的 main
# 其他需要手动 track
jj bookmark track <name> --remote=<remote>
# 查看tracked
jj bookmark list --tracked
```
## 检查清单
操作前快速检查:
- [ ] 不要用 `git add`
- [ ] 不要用 `jj co` 或 `jj checkout`
- [ ] 用 `jj commit` 而不是 `git commit`
- [ ] 用 `jj bookmark` 而不是 `git branch`
- [ ] 用 `jj new @ A` 而不是 `git merge`
- [ ] 用 `jj rebase -b` 或 `-s` 变基
- [ ] 用 `jj new @-` 暂存而不是 `git stash`
- [ ] 分叉的 change ID 需要用 commit ID 明确指定
Successfully wrote 2867 bytes to ~/projects/public-skills/skills/jujutsu/references/pitfalls.md
现在让我创建一个新的文件来补充关于 colocated workspaces、multiple remotes、divergent changes 等内容:
File: ~/projects/public-skills/skills/jujutsu/references/advanced.md
Content (3479 chars):
# 高级主题
> 基于官方文档的补充内容
## Colocated Workspaces(共存工作区)
jj 和 git 可以共存于同一目录,方便迁移和混用工具。
### 创建
```bash
# 新建共存工作区(默认行为)
jj git init
# 或
jj git clone <url>
# 禁用共存
jj git init --no-colocate
jj git clone --no-colocate <url>
```
### 混用 jj 和 git
```bash
# 在共存工作区中可以:
jj st
git status # 也可以用,但可能显示"detached HEAD"
# jj 命令会自动 import/export 到 git
# 但建议主要用 jj,git 只做只读操作
```
### 切换共存状态
```bash
# 查看当前状态
jj git colocation status
# 启用共存
jj git colocation enable
# 禁用共存
jj git colocation disable
```
### 注意事项
- jj 命令会频繁自动 import/export,可能导致分支冲突
- 大型仓库中 jj 会变慢(每次命令都执行 git import)
- 有冲突文件时 Git 工具可能出问题
## Multiple Remotes(多远程)
### 典型工作流
#### Fork 工作流(贡献上游)
```bash
# 1. 配置同时从多个 remote 拉取
jj config set --repo git.fetch '["upstream", "origin"]'
# 2. 推送只用 origin
jj config set --repo git.push origin
# 3. 跟踪远程 bookmark
jj bookmark track main # 跟踪 origin/main
jj bookmark track main --remote=upstream # 也跟踪 upstream
# 4. 设置 trunk(作为 immutable 基础)
jj config set --repo 'revset-aliases."trunk()"' main@upstream
```
#### 集成工作流(独立仓库)
```bash
# 1. 只从 origin 拉取和推送
jj config set --repo git.fetch '["origin"]'
# 2. 只跟踪 origin
jj bookmark track main --remote=origin
jj bookmark untrack main --remote=upstream
# 3. 设置 trunk 为 origin
jj config set --repo 'revset-aliases."trunk()"' main@origin
```
### Remote Bookmarks 引用
```bash
# 引用远程 bookmark
main@origin # origin 上的 main
main@upstream # upstream 上的 main
# 在新远程上创建
jj new main@upstream
```
## Divergent Changes(分叉变化)
当同一 change ID 有多个可见 commit 时发生。
### 原因
1. 本地和远程同时修改了同一个 change
2. 从不同 workspace 操作同一 change
3. 并发操作导致
### 识别
```bash
jj log
# 显示:
# mzvwutvl/0 ... (divergent)
# mzvwutvl/1 ... (divergent)
```
### 解决策略
#### 1. 放弃一个
```bash
# 放弃不需要的版本
jj abandon <commit-id>
```
#### 2. 生成新 change ID
```bash
# 为一个 commit 生成新的 change ID
jj metaedit --update-change-id <commit-id>
```
#### 3. 合并内容
```bash
# 把一个 squash 到另一个
jj squash --from <source-commit-id> --into <target-commit-id>
```
#### 4. 忽略
如果不影响工作,可以暂时不管。
## Operation Log(操作日志)
jj 记录每次修改仓库的操作,比 Git 的 reflog 更强大。
### 查看
```bash
# 操作列表
jj op log
# 带 diff 的操作历史
jj op log -p
```
### 撤销
```bash
# 撤销上一次操作
jj undo
# 撤销到特定操作
jj undo --at-operation <operation-id>
```
### 恢复到之前状态
```bash
# 恢复整个仓库到某操作时的状态
jj op restore --at-operation <operation-id>
```
### 时光倒流
```bash
# 在某个操作的状态下运行命令(不修改)
jj --at-operation <operation-id> log
```
## Conflict 深入
### 冲突类型
1. **文件冲突**:同一文件同一位置被不同修改
2. **Bookmark 冲突**:本地和远程 bookmark 移动冲突
3. **Change 分叉**:同一 change ID 多个可见 commit
### 冲突解决
```bash
# 1. 创建新 commit 在冲突 commit 上
jj new <conflicted-commit>
# 2. 编辑文件解决冲突
# 编辑冲突标记...
# 3. 标记解决
jj resolve <file>
# 4. 如果有多个冲突文件,全部解决后
jj squash
```
### 冲突标记风格
可配置(默认 "diff"):
```bash
# diff 风格(默认)
jj config set --user ui.conflict-marker-style diff
# snapshot 风格
jj config set --user ui.conflict-marker-style snapshot
# git 风格
jj config set --user ui.conflict-marker-style git
```
## Filesets(文件集)
类似 revset 但用于文件选择。
### 语法
```bash
# 文件路径
jj diff file.txt
# glob 模式
jj diff 'glob:*.rs'
# cwd 前缀
jj diff 'cwd:src/'
# root 前缀
jj diff 'root:src/'
# 组合
jj diff 'src ~ glob:**/test*.rs'
jj diff 'glob:*.rs | glob:*.md'
```
### 使用场景
```bash
# 拆分时只选部分文件
jj split 'glob:*.rs'
# 查看特定目录差异
jj diff 'root:src/'
```
## 配置示例
### 用户配置
```toml
[user]
name = "Your Name"
email = "your@email.com"
[ui]
color = "auto"
default-command = ["log", "--reversed"]
[diff]
color-words.max-inline-alternation = 3
```
### 自动签名
```toml
[signing]
behavior = "inline"
```
Successfully wrote 3479 bytes to ~/projects/public-skills/skills/jujutsu/references/advanced.md
现在让我提交并推送更新:
Command:
cd ~/projects/public-skills && git add -A && git status
On branch feature/jujutsu
Your branch is up to date with 'origin/feature/jujutsu'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: skills/jujutsu/SKILL.md
new file: skills/jujutsu/references/advanced.md
modified: skills/jujutsu/references/commands.md
modified: skills/jujutsu/references/pitfalls.md
好的,让我提交并推送:
Command:
cd ~/projects/public-skills && git commit -m "feat: add advanced topics - colocated workspaces, multiple remotes, divergent changes, filesets"
[feature/jujutsu 39313ee] feat: add advanced topics - colocated workspaces, multiple remotes, divergent changes, filesets
4 files changed, 367 insertions(+), 19 deletions(-)
create mode 100644 skills/jujutsu/references/advanced.md
让我推送更新:
Command:
cd ~/projects/public-skills && git push
To github.com:lambda610/skills.git
65287b5..39313ee feature/jujutsu -> feature/jujutsu
完成了!让我告诉 Yelo 更新内容:
Yelo asks if I've taken notes of what I learned. Let me check if there's any notes about jujutsu in ~/notes/.
Command:
ls -la ~/notes/ 2>/dev/null || echo "notes 目录不存在"
[CONDENSED]
There's already a jj-vcs.md file! Let me check its content and update it with the new things I learned.
# Jujutsu (jj) VCS 研究笔记
**来源**:
- https://github.com/jj-vcs/jj
- https://pksunkara.com/thoughts/git-experts-should-try-jujutsu
- https://utensil.bearblog.dev/jj/
- https://news.ycombinator.com/item?id=45672280
**日期**: 2026-02-26
**标签**: vcs, git, jj, jujutsu
---
## 什么是 jj
Jujutsu (jj) 是一个用 Rust 编写的 Git 兼容版本控制系统,目标是「既简单又强大」。
**亮点**:
- ⭐ 26k+ stars
- 🦀 100% Rust
- Git 兼容
---
## 核心特点
### 1. 无 staging area
- 没有显式的索引或暂存区
- 工作副本即提交(working-copy-as-a-commit)
- 默认全交,用 `restore` 排除不想交的
### 2. 匿名分支
- 像 Mercurial 一样,分支是匿名的
- 不用为每个小改动起名
### 3. 自动 rebase
- 修改任意 commit 后,所有后继自动 rebase
- 冲突解决会传播到后续 commit
- 这是最杀手级的特性
### 4. 操作日志 & 撤销
- 记录所有操作,可随时回溯
- `jj op log` 查看,`jj undo` 撤销
### 5. 冲突 first-class
- 冲突被作为一等公民处理
- 支持自动传播解决
### 6. Bookmark(书签)
- jj 的分支叫 bookmark,对应 Git 的 branch
- 推送到远程:`jj git push -b main` 或 `jj git push --change @`
- 跟踪远程分支:`jj bookmark track main`
---
## 基础命令
```bash
# 初始化
jj init
jj git init --git-repo=. # 现有 Git 项目
# 查看
jj log # 提交历史
jj status # 当前状态
# 提交
jj commit -m "message"
# 修改历史
jj edit <commit> # 修改某个提交
jj restore <file> # 排除文件(不提交)
jj squash # 合并提交
jj reword # 修改提交信息
jj split # 拆分提交
# Git 互操作
jj git push
jj git pull
jj git export
```
---
## 与 Git 的区别
| Git | jj |
|-----|-----|
| staging area | 无 staging,全交或 restore 排除 |
| 分支名重要 | 匿名分支 |
| rebase 需手动 | 自动 rebase |
| 难以撤销 | op log + undo |
| 冲突只是文本 | 冲突是 first-class |
---
## 命令对比(来自 pksunkara)
| 场景 | Git | jj |
|------|-----|-----|
| 修改旧提交 | `git rebase -i` → 标记 edit → amend → continue | `jj edit <change-id>` 直接搞定 |
| 拆分提交 | rebase → reset → `git add -p` → 逐个 commit | `jj split <change-id>` 交互式 diff 编辑器 |
| 创建 PR | checkout -b → commit → push → gh pr create | `jj new -m` → `jj git push --change @` 直接推送 |
---
## 关键概念(来自 utensil day 1 体验)
- **Change vs Commit**: Git 的 commit 是固定的,jj 的 change 是可塑的——可以随意修改、重新排序,历史会自动重塑
- **Bookmark**: 类似 Git 的分支,但不会自动跟随最新 change(需要手动移动)
- **Working copy**: `@` 表示当前工作副本,已经是"未来的 commit",不用 staging
- **`@`**: 当前 working copy
- **`@-`**: 上一个 commit
**常用命令**:
- `jj` / `jj l` - 查看日志
- `jj s` - 状态
- `jj ci` - 交互式选择文件/片段 commit
- `jj cim <msg>` - 带消息 commit
- `jj n` - 从任意 change 创建新分支
- `jj e <revset>` - 编辑旧 change
---
## HN 讨论要点(2025-10,376 points)
### 优势观点
- **"先乱提交,后期整理"** 适合 AI 辅助编码:快速迭代,让 jj 自动保存每个改动,最后用 `squash` 整理成干净的 commit
- StGit 维护者已转向 jj:`jj squash` 让 `stg squash` 显得"业余"
- 对 stacked PRs 支持更好
### 争议点
- **Magit 用户**:jj 的 hunk 分割体验像"回到石器时代",staging/commiting 30x 更频繁
- **心智模型转变**:不再需要 staging/committing 的分离概念,一切都是 change
- 有人担心"又多了个 VCS 学习成本",团队里混用麻烦
### 适合场景
- ✅ Solo 项目
- ✅ 全员都用 jj
- ✅ 频繁 rebase、喜欢整理历史
- ❌ 团队强制 Git 工作流
---
## 适合谁用
✅ **适合**:
- 习惯把一个功能拆成多个小 commit
- 经常 rebase、改历史
- 想要更简单的本地 VCS
❌ **不适合**:
- 团队强制 Git 工作流
- 不习惯改历史
---
## 参考
- 官网: https://jj-vcs.dev
- 文档: https://docs.jj-vcs.dev
There's already a jj-vcs.md file but it was created on 2026-02-26. Now it's 2026-03-06. The content was from earlier research before reading the official docs. The new content I learned from the official docs should be added/updated. Let me update the notes with the more accurate information from the official docs.
File: ~/notes/jj-vcs.md
Content (5042 chars):
# Jujutsu (jj) VCS 研究笔记
**来源**:
- https://www.jj-vcs.dev/latest/ (官方文档 - 2026-03-06 完整阅读)
- https://github.com/jj-vcs/jj
- https://pksunkara.com/thoughts/git-experts-should-try-jujutsu
- https://utensil.bearblog.dev/jj/
- https://news.ycombinator.com/item?id=45672280
**日期**: 2026-03-06
**标签**: vcs, git, jj, jujutsu
---
## 什么是 jj
Jujutsu (jj) 是一个用 Rust 编写的 Git 兼容版本控制系统,目标是「既简单又强大」。
**亮点**:
- ⭐ 26k+ stars
- 🦀 100% Rust
- Git 兼容
---
## 核心概念(官方文档精炼)
### Change vs Commit
- **Commit**:文件的快照 + 元数据(作者、日期、父提交)
- **Change**:commit 的演化历史,用 change ID 标识(类似 Gerrit 的 Change-Id)
- **Working-copy commit**:当前工作目录对应的 commit(@ 符号)
### Change ID vs Commit ID
- **Change ID**:jj 特有,16 字节随机生成,格式如 `kntqzsqt`,会保持不变
- **Commit ID**:Git 兼容的提交哈希,会随内容变化
### Bookmark vs Branch
- **Bookmark**:指向 commit 的命名指针,类似 Git branch
- **无"当前 bookmark"** — jj 没有活跃分支的概念
- **Tracked bookmark**:自动跟踪远程同名 bookmark
---
## 与 Git 的根本差异
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 是可编辑的 change |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| `git stash` 暂存 | 用 `jj new @-` |
| 冲突必须立即解决 | jj 冲突可延迟处理 |
| checkout 切换分支 | 用 `jj new` 或 `jj edit`(无 checkout) |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,类似 Git branch 但有 tracked 概念
5. **Revsets** — 强大的查询语法,能表达复杂条件
6. **无 checkout** — 用 `jj new` 或 `jj edit` 切换
7. **冲突不阻塞** — 冲突记录在 commit 中,可稍后解决
---
## 常用命令(官方推荐)
```bash
# 查看状态
jj st # 当前变更(相当于 git status)
jj log # 历史
jj log --graph # 图形化历史
# 操作变更(无需 add!)
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(自动包含所有修改)
jj squash # 合并到父提交(类似 git commit --amend)
jj restore <path> # 撤销文件修改
# ⚠️ 没有 jj co 或 jj checkout!
# 切换到某 bookmark:用 jj new <bookmark>
# 编辑某 commit:用 jj edit <revision>
# Bookmarks
jj bookmark list # 列出 bookmarks
jj bookmark create <name> -r <revision> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <revision> # 移动 bookmark
jj bookmark track <name> --remote=<remote> # 跟踪远程 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动 bookmark
jj rebase -s <commit> -o <dest> # 移动 commit 及后代
# 远程操作
jj git fetch # 拉取
jj git push # 推送
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
```
---
## 命令对照表(官方)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | |
| `git diff` | `jj diff` | |
| `git add` | ❌ 不需要 | jj 自动追踪 |
| `git commit` | `jj commit -m "msg"` | |
| `git commit --amend` | `jj squash` | |
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | |
| `git branch` | `jj bookmark list` | |
| `git merge A` | `jj new @ A` | |
| `git rebase B A` | `jj rebase -b A -o B` | |
| `git stash` | `jj new @-` | |
| `git reset --hard` | `jj abandon` | |
| `git reflog` | `jj op log` | |
---
## Revset 查询语法
### 常用符号
| 符号 | 含义 |
|------|------|
| `@` | 当前 working-copy commit |
| `@-` | 当前 commit 的父提交 |
| `root()` | 仓库根提交(虚拟 commit,hash 全为 0) |
| `bookmarks()` | 所有本地 bookmark |
### 运算符
| 运算符 | 含义 |
|--------|------|
| `::` | 祖先范围(包含自己) |
| `..` | 不包含祖先 |
| `|` | 并集 |
| `&` | 交集 |
| `~` | 差集 |
### 示例
```bash
jj log -r ::@ # 当前 commit 的祖先链
jj log -r 'all()' # 所有可见 commit
jj log -r main.. # main 分支后的 commit
```
---
## 高级主题
### Colocated Workspaces
jj 和 git 可共存于同一目录:
- `.jj/` + `.git/` 共存
- jj 和 git 命令可混用
- jj 自动 import/export 到 git
```bash
# 创建共存工作区(默认)
jj git init
jj git clone <url>
# 禁用共存
jj git init --no-colocate
```
### Multiple Remotes
Fork 工作流:
```bash
jj config set --repo git.fetch '["upstream", "origin"]'
jj config set --repo git.push origin
jj bookmark track main
jj config set --repo 'revset-aliases."trunk()"' main@upstream
```
### Divergent Changes
当同一 change ID 有多个可见 commit 时:
```bash
# 解决策略
jj abandon <unwanted-commit-id> # 放弃一个
jj metaedit --update-change-id <commit-id> # 生成新 change ID
jj squash --from <source> --into <target> # 合并两个
```
### Operation Log
比 Git reflog 更强大:
```bash
jj op log # 查看操作
jj undo # 撤销
jj op restore --at-operation <id> # 恢复到某状态
```
---
## 常见错误
### 🔴 严重
1. **用 `git add`** — jj 自动追踪,不需要
2. **用 `jj co` 或 `jj checkout`** — 根本没有这些命令!用 `jj new` 或 `jj edit`
3. **用 `git stash`** — 用 `jj new @-`
4. **用 `git merge`** — 用 `jj new @ A`
### 🟠 易错
1. **混淆 `-b` 和 `-s`**
- `-b` = 移动 bookmark
- `-s` = 移动 commit + 后代
2. **忽略 divergent changes** — 需要用 commit ID 明确指定
3. **`jj file untrack` 不生效** — 需要先匹配 ignore pattern
---
## 适合谁用
✅ **适合**:
- Solo 项目
- 习惯把一个功能拆成多个小 commit
- 经常 rebase、改历史
- 想要更简单的本地 VCS
❌ **不适合**:
- 团队强制 Git 工作流
- 不习惯改历史
---
## 参考
- 官网: https://jj-vcs.dev
- 文档: https://docs.jj-vcs.dev/latest/
- Git 命令表: https://www.jj-vcs.dev/latest/git-command-table/
- Git 专家指南: https://www.jj-vcs.dev/latest/git-experts/
Successfully wrote 5043 bytes to ~/notes/jj-vcs.md
Good. I've updated the notes with the more accurate information from the official docs.
Yelo wants me to review the jujutsu skill I created. Let me read through it carefully and check for any issues.
---
name: jujutsu
description: Use Jujutsu (jj) for version control in jj-enabled projects. Applies when the project uses jj (has .jj/ directory, README specifies jj, or user requests jj).
---
# Jujutsu 使用指南
Jujutsu (jj) 是新一代分布式版本控制工具,兼容 Git 仓库但用法有根本差异。
## 何时使用
**仅在明确使用 jj 的项目中使用此 skill。** 判断方法:
- 存在 `.jj/` 目录
- 项目 README 明确要求用 jj
- 用户明确指定用 jj
对于普通 Git 项目,使用标准的 Git 工具。
## 心智模型(与 Git 的根本差异)
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 是可编辑的 change |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| `git stash` 暂存 | 用 `jj new @-` 或 `jj shelf` |
| 冲突必须立即解决 | jj 冲突可延迟处理 |
| checkout 切换分支 | 用 `jj new` 或 `jj edit`(无 checkout) |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,类似 Git branch 但有 tracked 概念
5. **Revsets** — 强大的查询语法,能表达复杂条件
6. **无 checkout** — 用 `jj new` 或 `jj edit` 切换
7. **冲突不阻塞** — 冲突记录在 commit 中,可稍后解决
## 核心概念
### Change vs Commit
- **Commit**:文件的快照 + 元数据(作者、日期、父提交)
- **Change**:commit 的演化历史,用 change ID 标识(类似 Gerrit 的 Change-Id)
- **Working-copy commit**:当前工作目录对应的 commit(@ 符号)
### Change ID vs Commit ID
- **Change ID**:jj 特有,16 字节随机生成,格式如 `kntqzsqt`,会保持不变
- **Commit ID**:Git 兼容的提交哈希,会随内容变化
### Bookmark vs Branch
- **Bookmark**:指向 commit 的命名指针,类似 Git branch
- **无"当前 bookmark"** — jj 没有活跃分支的概念
- **Tracked bookmark**:跟踪远程同名 bookmark
### Colocated Workspaces
jj 和 git 可共存于同一目录:
- `.jj/` + `.git/` 共存
- jj 和 git 命令可混用
- jj 自动 import/export 到 git
## 常用命令速查
```bash
# 查看状态
jj st # 当前变更(相当于 git status)
jj log # 历史
jj log --graph # 图形化历史
# 操作变更(无需 add)
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(自动包含所有修改)
jj squash # 合并到父提交(类似 git commit --amend)
jj restore <path> # 撤销文件修改
# 注意:没有 jj co 或 jj checkout!
# 切换到某 bookmark:用 jj new <bookmark>
# 编辑某 commit:用 jj edit <revision>
# Bookmarks(类似 branch,但不同)
jj bookmark list # 列出 bookmarks
jj bookmark create <name> -r <revision> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <revision> # 移动 bookmark
jj bookmark track <name> --remote=<remote> # 跟踪远程 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动 bookmark 及其指向的 commit
jj rebase -s <commit> -o <dest> # 移动 commit 及其后代
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
# 多远程
jj config set --repo git.fetch '["upstream", "origin"]'
jj bookmark track main # 跟踪远程 bookmark
```
## 常见工作流
### 日常提交
```bash
# 1. 查看变更
jj st
jj diff
# 2. 提交(无需 add!)
jj commit -m "feat: add new feature"
# 3. 查看历史
jj log
```
### 修改历史提交
```bash
# 修改当前提交的描述
jj describe -m "new message"
# 把当前变更合并到上一个提交
jj squash
# 把变更 squash 到指定提交
jj squash --into <commit>
```
### 创建新分支
```bash
# 相当于 git checkout -b topic main
jj new main
jj bookmark create topic
# 或者一步到位:
jj new main -b topic
```
### 变基
```bash
# 移动 bookmark A 到 B 上(类似 git rebase)
jj rebase -b A -o B
# 移动 commit 及其后代到新基础
jj rebase -s <commit> -o <dest>
```
### 处理冲突
```bash
# 1. 冲突不会中断操作,会创建 conflicted change
# 2. 创建新 commit 来解决冲突
jj new <conflicted-commit>
# 3. 解决文件中的冲突标记
# 编辑文件...
# 4. 标记已解决
jj resolve <file>
# 5. squash 到原提交
jj squash
```
### 临时保存当前工作
```bash
# 相当于 git stash:创建兄弟 commit
jj new @-
# 恢复:用 jj edit <commit> 回到之前的 commit
```
### Divergent Changes(分叉变化)
当同一 change ID 有多个可见 commit 时:
```bash
# 查看
jj log # 显示 divergent 标记
# 解决策略
jj abandon <unwanted-commit-id> # 放弃一个
jj metaedit --update-change-id <commit-id> # 生成新 change ID
jj squash --from <source> --into <target> # 合并两个
```
## 关键命令对照
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | |
| `git diff` | `jj diff` | |
| `git add` | ❌ 不需要 | jj 自动追踪 |
| `git commit` | `jj commit -m "msg"` | |
| `git commit --amend` | `jj squash` | |
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | |
| `git branch` | `jj bookmark list` | |
| `git merge A` | `jj new @ A` | |
| `git rebase B A` | `jj rebase -b A -o B` | |
| `git stash` | `jj new @-` | |
| `git reset --hard` | `jj abandon` | |
| `git reflog` | `jj op log` | |
## 注意事项
1. **不要用 `git add`** — jj 自动追踪
2. **不要用 `jj co`** — 用 `jj new` 或 `jj edit`
3. **`jj commit` 自动包含所有修改** — 不需要 `-a`
4. **冲突不阻塞** — 可以继续工作,稍后再解决
5. **`jj new` 创建的是 change** — 是可编辑的空 commit
6. **Bookmarks 有 tracked 概念** — 类似 Git 的 upstream
## Revset 快速参考
```bash
# 常用符号
@ # 当前 working-copy commit
@- # 父提交
root() # 根提交
bookmarks() # 所有 bookmark
# 运算符
:: # 祖先(包含自己)
.. # 不包含祖先
~ # 差集
| # 并集
& # 交集
# 示例
jj log -r ::@ # 当前 commit 的祖先链
jj log -r 'all()' # 所有可见 commit
jj log -r main.. # main 分支后的 commit
```
## 获取帮助
```bash
jj help
jj help <subcommand>
```
更多内容:见 `references/` 目录
Let me carefully review this skill and identify potential issues:
-
jj new <bookmark>for checkout - I saidjj new <bookmark>is likegit checkout <branch>, but actuallyjj new <bookmark>creates a NEW change on top of the bookmark, not "checkout" to it. The correct way to "checkout" (i.e., edit) an existing commit isjj edit <revision>. -
Multiple remotes - The config example uses
jj config set --repowhich might need--userfor user-level config -
jj rebase -b A -o B- Actually rebase -b moves a bookmark. But wait, let me double-check the tutorial docs again... Yes,-bmoves the bookmark and its commit, but not descendants.-smoves the commit and its descendants. -
jj new @ Afor merge - This creates a new change that is a merge commit with A as the second parent. That seems correct. -
jj shelf- I mentioned it as an alternative tojj new @-, but let me verify this exists... Actually from the docs,jj shelfexists but it's less commonly used thanjj new @-. -
The description of
jj new <bookmark>- I said it's likegit checkout -b, which creates a NEW branch. But if you just want to switch to an existing bookmark, you needjj edit.jj newalways creates a new change. -
Missing mention of
jj util gc- For large repos with colocated workspaces, this command helps with performance. -
jj bookmark track main- Without specifying --remote, it tracks the default remote. This might be confusing.
Let me provide a comprehensive review.
Yelo 让我再确认一下官方文档中的内容,特别是:
- jj new 的行为 - 是否真的只是创建新 commit 而不是切换
- jj edit 的用途
- 变基命令的正确对应
- bookmark track 的行为
让我再仔细看一下官方文档的相关部分。
Command:
curl -s "https://www.jj-vcs.dev/latest/cli-reference/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | grep -A 20 "^jj new"
[CONDENSED]
OK,所以 jj new 确实是创建一个新的 empty change,并且默认会在 working copy 中编辑它。让我继续看 jj edit 的文档。
Command:
curl -s "https://www.jj-vcs.dev/latest/cli-reference/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | grep -A 30 "^jj edit"
[CONDENSED]
OK,jj edit 确实是"设置指定 revision 为 working-copy revision",类似于 checkout。
让我再确认 rebase 命令的 -b 和 -s 的区别。
Command:
curl -s "https://www.jj-vcs.dev/latest/cli-reference/" -H "User-Agent: Mozilla/5.0" | sed -n '/<article/,/<\/article/p' | sed 's/<[^>]*>//g' | sed 's/ / /g' | grep -A 50 "^jj rebase"
[CONDENSED]
OK,现在我理解了:
-
jj new- 创建新的 empty change,默认会在 working copy 中编辑它。指定多个 revision 作为参数可以创建 merge commit。 -
jj edit- 设置指定的 revision 为 working-copy revision。这才是"切换"到某个 commit 进行编辑。 -
jj rebase:-s, --source- 移动指定的 revision 及其后代-b, --branch- 移动整个"分支"(包含指定 revision 及其祖先中不在 destination 祖先中的部分)-r, --revisions- 只移动指定的 revision,不包含后代- 默认是
-b @
所以我之前写的对照表确实有问题:
git checkout <branch>=jj new <bookmark>是错的- 应该是
jj edit <revision>更接近"checkout"的行为
让我修正这些问题。
File: ~/projects/public-skills/skills/jujutsu/SKILL.md
Content (5532 chars):
---
name: jujutsu
description: Use Jujutsu (jj) for version control in jj-enabled projects. Applies when the project uses jj (has .jj/ directory, README specifies jj, or user requests jj).
---
# Jujutsu 使用指南
Jujutsu (jj) 是新一代分布式版本控制工具,兼容 Git 仓库但用法有根本差异。
## 何时使用
**仅在明确使用 jj 的项目中使用此 skill。** 判断方法:
- 存在 `.jj/` 目录
- 项目 README 明确要求用 jj
- 用户明确指定用 jj
对于普通 Git 项目,使用标准的 Git 工具。
## 心智模型(与 Git 的根本差异)
### ❌ 不要按 Git 思维操作
| Git 思维 | 问题 |
|---------|------|
| `git add` | jj 无暂存区,不需要 add |
| commit 后不能改 | jj 的 commit 是可编辑的 change |
| 用 branch 管理分支 | jj 用 bookmarks,是轻量指针 |
| `git stash` 暂存 | 用 `jj new @-` |
| 冲突必须立即解决 | jj 冲突可延迟处理 |
| checkout 切换 | 用 `jj edit`(无 checkout) |
### ✅ 正确的心智模型
1. **自动追踪** — jj 自动追踪所有修改,无需 `git add`
2. **可变提交** — commit 是可编辑的"change",随时可修改
3. **操作可撤销** — 几乎所有操作都能用 `jj undo` 撤销
4. **Bookmarks** — 轻量标记,类似 Git branch 但有 tracked 概念
5. **Revsets** — 强大的查询语法,能表达复杂条件
6. **无 checkout** — 用 `jj edit` 切换到某 commit
7. **冲突不阻塞** — 冲突记录在 commit 中,可稍后解决
## 核心概念
### Change vs Commit
- **Commit**:文件的快照 + 元数据(作者、日期、父提交)
- **Change**:commit 的演化历史,用 change ID 标识(类似 Gerrit 的 Change-Id)
- **Working-copy commit**:当前工作目录对应的 commit(@ 符号)
### Change ID vs Commit ID
- **Change ID**:jj 特有,16 字节随机生成,格式如 `kntqzsqt`,会保持不变
- **Commit ID**:Git 兼容的提交哈希,会随内容变化
### Bookmark vs Branch
- **Bookmark**:指向 commit 的命名指针,类似 Git branch
- **无"当前 bookmark"** — jj 没有活跃分支的概念
- **Tracked bookmark**:自动跟踪远程同名 bookmark
### Colocated Workspaces
jj 和 git 可共存于同一目录:
- `.jj/` + `.git/` 共存
- jj 和 git 命令可混用
- jj 自动 import/export 到 git
## 常用命令速查
```bash
# 查看状态
jj st # 当前变更(相当于 git status)
jj log # 历史
jj log --graph # 图形化历史
# 操作变更(无需 add)
jj diff # 查看当前变更
jj describe # 修改提交信息
jj commit -m "message" # 提交(自动包含所有修改)
jj squash # 合并到父提交(类似 git commit --amend)
jj restore <path> # 撤销文件修改
# ⚠️ 没有 checkout!
# 切换到某 commit 编辑:用 jj edit <revision>
# 创建新 change:用 jj new
# 创建与切换
jj new # 创建新 empty change(当前 @ 的子提交)
jj new <revision> # 基于某 revision 创建新 change
jj new -b <bookmark> # 创建新 change 并设置 bookmark
jj edit <revision> # 切换到某 commit 进行编辑(类似 checkout)
# Bookmarks
jj bookmark list # 列出 bookmarks
jj bookmark create <name> -r <revision> # 创建 bookmark
jj bookmark delete <name> # 删除 bookmark
jj bookmark move <name> --to <revision> # 移动 bookmark
jj bookmark track <name> --remote=<remote> # 跟踪远程 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动整个分支
jj rebase -s <commit> -o <dest> # 移动 commit 及其后代
jj rebase -r <commit> -o <dest> # 只移动指定 commit
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
# 多远程
jj config set --user git.fetch '["upstream", "origin"]'
jj bookmark track main --remote=origin # 跟踪 origin/main
```
## 常见工作流
### 日常提交
```bash
# 1. 查看变更
jj st
jj diff
# 2. 提交(无需 add!)
jj commit -m "feat: add new feature"
# 3. 查看历史
jj log
```
### 修改历史提交
```bash
# 修改当前提交的描述
jj describe -m "new message"
# 把当前变更合并到上一个提交
jj squash
# 把变更 squash 到指定提交
jj squash --into <commit>
```
### 编辑现有 commit(类似 git checkout)
```bash
# 切换到某 commit 进行编辑
jj edit <revision>
# 之后的所有修改都会 amend 这个 commit
```
### 创建新分支
```bash
# 创建新 change 并设置 bookmark
jj new main -b topic
```
### 变基
```bash
# 移动整个分支(包含所有后代)
jj rebase -b topic -o main
# 移动单个 commit 及其后代
jj rebase -s <commit> -o <dest>
# 只移动单个 commit(不包含后代)
jj rebase -r <commit> -o <dest>
```
### 处理冲突
```bash
# 1. 冲突不会中断操作,会创建 conflicted change
# 2. 创建新 commit 来解决冲突
jj new <conflicted-commit>
# 3. 解决文件中的冲突标记
# 编辑文件...
# 4. 标记已解决
jj resolve <file>
# 5. squash 到原提交
jj squash
```
### 临时保存当前工作
```bash
# 相当于 git stash:创建兄弟 commit
jj new @-
# 恢复:用 jj edit <commit> 回到之前的 commit
```
### Divergent Changes(分叉变化)
当同一 change ID 有多个可见 commit 时:
```bash
# 查看
jj log # 显示 divergent 标记
# 解决策略
jj abandon <unwanted-commit-id> # 放弃一个
jj metaedit --update-change-id <commit-id> # 生成新 change ID
jj squash --from <source> --into <target> # 合并两个
```
## 关键命令对照
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | |
| `git diff` | `jj diff` | |
| `git add` | ❌ 不需要 | jj 自动追踪 |
| `git commit` | `jj commit -m "msg"` | |
| `git commit --amend` | `jj squash` | |
| `git checkout <commit>` | `jj edit <revision>` | **切换到某 commit 编辑** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并设置 bookmark |
| `git branch` | `jj bookmark list` | |
| `git switch <branch>` | `jj new <bookmark>` | **创建新 change** |
| `git merge A` | `jj new @ A` | 创建 merge commit |
| `git rebase A B` | `jj rebase -s A -o B` | A 及其后代移到 B 上 |
| `git stash` | `jj new @-` | |
| `git reset --hard` | `jj abandon` | |
| `git reflog` | `jj op log` | |
**注意**:
- `jj new` **不是** `git checkout`,而是创建新 change
- `jj edit` 才是类似"切换到某 commit"的命令
## 注意事项
1. **不要用 `git add`** — jj 自动追踪
2. **没有 checkout** — 用 `jj edit` 切换,用 `jj new` 创建
3. **`jj commit` 自动包含所有修改** — 不需要 `-a`
4. **冲突不阻塞** — 可以继续工作,稍后再解决
5. **`jj new` 创建的是 change** — 是可编辑的空 commit
6. **Bookmarks 有 tracked 概念** — 类似 Git 的 upstream
## Revset 快速参考
```bash
# 常用符号
@ # 当前 working-copy commit
@- # 父提交
root() # 根提交
bookmarks() # 所有 bookmark
# 运算符
:: # 祖先(包含自己)
.. # 不包含祖先
~ # 差集
| # 并集
& # 交集
# 示例
jj log -r ::@ # 当前 commit 的祖先链
jj log -r 'all()' # 所有可见 commit
jj log -r main.. # main 分支后的 commit
```
## 获取帮助
```bash
jj help
jj help <subcommand>
```
更多内容:见 `references/` 目录
Successfully wrote 5532 bytes to ~/projects/public-skills/skills/jujutsu/SKILL.md
现在更新其他文件中的问题。
{
"status": "error",
"tool": "edit",
"error": "Could not find the exact text in ~/projects/public-skills/skills/jujutsu/references/commands.md. The old text must match exactly including all whitespace and newlines."
}
让我直接读取文件看看内容。
# 命令对照表(带解释)
> 基于官方文档:https://www.jj-vcs.dev/latest/git-command-table/
## 基础操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git status` | `jj st` | 查看当前工作状态 |
| `git diff` | `jj diff` | 查看未提交的修改 |
| `git diff HEAD` | `jj diff` | 同上,jj 默认比较 HEAD |
| `git diff <A>..<B>` | `jj diff -r A..B` | 比较两个提交 |
| `git add` | ❌ 不需要 | jj 自动追踪所有修改 |
| `git commit` | `jj commit -m "msg"` | 提交当前所有变更 |
| `git commit -a` | `jj commit` | 同上,jj 不需要 -a |
| `git commit --amend` | `jj squash` | 把当前变更合并到父提交 |
| `git restore <file>` | `jj restore <file>` | 撤销文件修改 |
| `git checkout -- <file>` | `jj restore <file>` | 同上 |
## 历史查看
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git log` | `jj log` | 查看历史 |
| `git log --oneline` | `jj log -r ::@` | 简洁格式 |
| `git log --graph` | `jj log --graph` | 图形化 |
| `git log --all` | `jj log -r 'all()'` | 查看所有 |
| `git show <rev>` | `jj show <rev>` | 查看提交详情 |
| `git blame <file>` | `jj file annotate <file>` | 文件注解 |
## ⚠️ 分支操作(关键区别!)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并切换 |
| `git branch` | `jj bookmark list` | 列出 |
| `git branch <name>` | `jj bookmark create <name>` | 创建 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动 |
**关键点**:
- jj 没有 `jj co` 或 `jj checkout` 命令!
- 用 `jj new <bookmark>` 创建新 change 并切换到它
- 用 `jj edit <revision>` 在 working copy 中编辑某 commit
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ A` | 合并(创建新 change) |
| `git rebase <B> <A>` | `jj rebase -b A -o B` | 移动 bookmark |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 移动 commit 及后代 |
**关键区别**:
- `-b` = 移动 bookmark 指向的 commit(不包含后代)
- `-s` = 移动指定 commit 及其所有后代
## 远程操作
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git fetch` | `jj git fetch` | 拉取 |
| `git pull` | `jj git fetch` (+ `jj new`) | |
| `git push` | `jj git push` | 推送 |
| `git push <remote> <branch>` | `jj git push --bookmark <name>` | |
| `git remote add` | `jj git remote add` | |
| `git branch -u <remote>/<branch>` | `jj bookmark track <name> --remote=<remote>` | 跟踪远程 |
## 暂存与撤销
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git stash` | `jj new @-` | 暂存到兄弟 commit |
| `git stash pop` | `jj edit <commit>` | 恢复 |
| `git reset --hard` | `jj abandon` | 放弃当前 change |
| `git reset --soft HEAD~` | `jj squash --from @-` | 保留修改 |
| `git cherry-pick <rev>` | `jj duplicate <rev> -o @` | 复制提交 |
## 撤销操作
[28 more lines in file. Use offset=81 to continue.]
现在让我修正这个文件。问题是:
git checkout <branch>=jj edit <revision>而不是jj new <bookmark>2. 需要更新关键点说明- 变基对照也有问题 -
git rebase B A把 A 变基到 B 上,应该对应-s
Old:
## ⚠️ 分支操作(关键区别!)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git checkout <branch>` | `jj new <bookmark>` | **没有 jj co!** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并切换 |
| `git branch` | `jj bookmark list` | 列出 |
| `git branch <name>` | `jj bookmark create <name>` | 创建 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动 |
**关键点**:
- jj 没有 `jj co` 或 `jj checkout` 命令!
- 用 `jj new <bookmark>` 创建新 change 并切换到它
- 用 `jj edit <revision>` 在 working copy 中编辑某 commit
New:
## ⚠️ 分支操作(关键区别!)
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git checkout <commit>` | `jj edit <revision>` | **切换到某 commit 编辑** |
| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并设置 bookmark |
| `git switch <branch>` | `jj new <bookmark>` | 创建新 change |
| `git branch` | `jj bookmark list` | 列出 |
| `git branch <name>` | `jj bookmark create <name>` | 创建 |
| `git branch -d <name>` | `jj bookmark delete <name>` | 删除 |
| `git branch -f <name> <rev>` | `jj bookmark move <name> --to <rev>` | 移动 |
**关键点**:
- jj 没有 `jj co` 或 `jj checkout` 命令!
- 用 `jj edit <revision>` 切换到某 commit 进行编辑(类似 checkout)
- 用 `jj new` 创建新 change(不是切换!)
Successfully replaced text in ~/projects/public-skills/skills/jujutsu/references/commands.md.
现在修正变基部分。
Old:
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ A` | 合并(创建新 change) |
| `git rebase <B> <A>` | `jj rebase -b A -o B` | 移动 bookmark |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 移动 commit 及后代 |
**关键区别**:
- `-b` = 移动 bookmark 指向的 commit(不包含后代)
- `-s` = 移动指定 commit 及其所有后代
New:
## 变基与合并
| Git | Jujutsu | 说明 |
|-----|---------|------|
| `git merge <A>` | `jj new @ A` | 合并(创建新 merge commit) |
| `git rebase A B` | `jj rebase -s A -o B` | A 及其后代移到 B 上 |
| `git rebase --onto B A^ <branch>` | `jj rebase -s A -o B` | 同上 |
**关键区别**:
- `-b` = 移动整个分支(包含祖先,不含 destination 的祖先)
- `-s` = 移动指定 commit 及其所有后代
- `-r` = 只移动指定的 commit(不含后代)
Successfully replaced text in ~/projects/public-skills/skills/jujutsu/references/commands.md.
现在更新 pitfalls.md 中的类似错误。
# 常见错误与陷阱
> 基于官方文档,Agent 容易犯的错误。
## 🔴 严重错误
### 用 `git add`
**错误**:想暂存文件时用 `git add`
**问题**:jj 没有暂存区概念,`git add` 不会生效
**正确做法**:
```bash
# jj 自动追踪所有修改,直接提交即可
jj commit -m "message"
# 如果只想提交部分文件,用 jj split
jj split file1 file2
```
### 用 `jj co` 或 `jj checkout` 切换
**错误**:用 `jj co <bookmark>` 或 `jj checkout`
**问题**:jj 根本没有这两个命令!
**正确做法**:
```bash
# 创建新 change 在 bookmark 上(相当于 checkout -b)
jj new main
# 创建新 change 并设置 bookmark
jj new main -b myfeature
# 编辑现有 commit
jj edit <revision>
```
### 用 `git stash` 暂存
**错误**:用 `git stash`
**问题**:jj 没有 stash,用 `jj new @-` 创建兄弟 commit
**正确做法**:
```bash
# 临时保存当前工作(创建兄弟 commit)
jj new @-
# 恢复:用 jj edit 回到原 commit
jj edit <原commit>
```
### 用 `git merge`
**错误**:用 `jj merge`
**问题**:jj 没有 merge 命令
[146 more lines in file. Use offset=61 to continue.]
这个部分是对的 - 我写了 "jj 根本没有这两个命令",然后给了正确做法。让我看看是否有其他需要修正的地方。
# 恢复:用 jj edit 回到原 commit
jj edit <原commit>
```
### 用 `git merge`
**错误**:用 `jj merge`
**问题**:jj 没有 merge 命令
**正确做法**:
```bash
# 合并 A 到当前 commit
jj new @ A
```
## 🟠 易错操作
### 混淆 `-b` 和 `-s` 在 rebase
**误解**:`-b` 移动单个 commit
**正确**:
- `-b <bookmark>`:移动 bookmark 指向的 commit(不包含后代)
- `-s <commit>`:移动 commit 及其所有后代
```bash
# 错误
jj rebase -b A -o B # 移动 A(不含后代)
# 正确(移动 A 及其后代)
jj rebase -s A -o B
```
### `jj new` 不带参数
**误解**:`jj new` 等于 `git checkout -b`
**正确**:`jj new` 基于当前 `@` 创建新 change,不带 bookmark 名
```bash
# 创建新 change(无 bookmark)
jj new
# 创建并设置 bookmark
jj new -b <bookmark>
# 基于某提交创建
jj new <revision>
```
### 冲突后不知如何继续
**误解**:遇到冲突必须立即解决
**正确**:jj 允许先继续工作,稍后再解决
```bash
# 冲突后,jj 会创建 conflicted change
# 可以继续创建新 commit
jj new
# 之后回到冲突 commit 解决
jj new <conflicted-commit>
# 解决文件中的冲突
jj resolve <file>
jj squash
```
### 用 `jj file untrack` 但不设置 ignore
**错误**:直接 `jj file untrack`
**问题**:文件必须匹配 ignore pattern 才能 untrack
**正确做法**:
```bash
# 1. 先添加到 .gitignore
echo "file.txt" >> .gitignore
[77 more lines in file. Use offset=130 to continue.]
这部分看起来OK。让我检查 pitfalls.md 中的 rebase 描述是否正确,然后也更新它加入 -r 选项。
Old:
### 混淆 `-b` 和 `-s` 在 rebase
**误解**:`-b` 移动单个 commit
**正确**:
- `-b <bookmark>`:移动 bookmark 指向的 commit(不包含后代)
- `-s <commit>`:移动 commit 及其所有后代
```bash
# 错误
jj rebase -b A -o B # 移动 A(不含后代)
# 正确(移动 A 及其后代)
jj rebase -s A -o B
```
New:
### 混淆 `-b` 和 `-s` 在 rebase
**误解**:`-b` 移动单个 commit
**正确**:
- `-b <bookmark>`:移动整个分支(包含祖先,不含 destination 的祖先)
- `-s <commit>`:移动 commit 及其所有后代
- `-r <commit>`:只移动指定的 commit(不含后代)
```bash
# 移动 A 及其后代
jj rebase -s A -o B
# 移动整个分支
jj rebase -b bookmark -o main
# 只移动单个 commit
jj rebase -r A -o B
```
Successfully replaced text in ~/projects/public-skills/skills/jujutsu/references/pitfalls.md.
现在更新 SKILL.md 中的变基部分以保持一致。
Old:
### 变基
```bash
# 移动 bookmark A 到 B 上(类似 git rebase)
jj rebase -b A -o B
# 移动 commit 及其后代到新基础
jj rebase -s <commit> -o <dest>
```
New:
### 变基
```bash
# 移动整个分支
jj rebase -b topic -o main
# 移动 commit 及其后代
jj rebase -s <commit> -o <dest>
# 只移动单个 commit
jj rebase -r <commit> -o <dest>
```
{
"status": "error",
"tool": "edit",
"error": "Could not find the exact text in ~/projects/public-skills/skills/jujutsu/SKILL.md. The old text must match exactly including all whitespace and newlines."
}
让我检查 SKILL.md 中的变基部分。
Command:
grep -n "变基" ~/projects/public-skills/skills/jujutsu/SKILL.md
100:# 变基
160:### 变基
让我看看 160 行附近的内容。
```
### 变基
```bash
# 移动整个分支(包含所有后代)
jj rebase -b topic -o main
# 移动单个 commit 及其后代
jj rebase -s <commit> -o <dest>
# 只移动单个 commit(不包含后代)
jj rebase -r <commit> -o <dest>
```
### 处理冲突
```bash
# 1. 冲突不会中断操作,会创建 conflicted change
# 2. 创建新 commit 来解决冲突
jj new <conflicted-commit>
[94 more lines in file. Use offset=178 to continue.]
看起来 SKILL.md 已经被修正了(之前更新时可能已经包含正确的内容)。让我检查 100 行附近的重复部分。
jj bookmark track <name> --remote=<remote> # 跟踪远程 bookmark
# 变基
jj rebase -b <bookmark> -o <dest> # 移动整个分支
jj rebase -s <commit> -o <dest> # 移动 commit 及其后代
jj rebase -r <commit> -o <dest> # 只移动指定 commit
# 远程操作
jj git fetch # 拉取
jj git push # 推送
jj git push --bookmark <name> # 推送特定 bookmark
# 撤销
jj undo # 撤销上一次操作
jj op log # 查看操作日志
[159 more lines in file. Use offset=113 to continue.]
这部分也是正确的。让我确认 SKILL.md 中命令对照表的部分也是正确的。
Command:
grep -n -A2 "git checkout" ~/projects/public-skills/skills/jujutsu/SKILL.md | head -20
146:### 编辑现有 commit(类似 git checkout)
147-```bash
148-# 切换到某 commit 进行编辑
--
218:| `git checkout <commit>` | `jj edit <revision>` | **切换到某 commit 编辑** |
219:| `git checkout -b <name>` | `jj new <base> -b <name>` | 创建并设置 bookmark |
220-| `git branch` | `jj bookmark list` | |
221-| `git switch <branch>` | `jj new <bookmark>` | **创建新 change** |
--
229:- `jj new` **不是** `git checkout`,而是创建新 change
230-- `jj edit` 才是类似"切换到某 commit"的命令
231-
看起来已经正确了。让我提交这些修改并推送。
Command:
cd ~/projects/public-skills && git add -A && git diff --cached --stat
skills/jujutsu/SKILL.md | 66 +++++++++++++++++++++++------------
skills/jujutsu/references/commands.md | 18 +++++-----
skills/jujutsu/references/pitfalls.md | 14 +++++---
3 files changed, 62 insertions(+), 36 deletions(-)
让我提交并推送。
Command:
cd ~/projects/public-skills && git commit -m "fix: correct checkout/edit/new commands and rebase options"
[feature/jujutsu 79401fa] fix: correct checkout/edit/new commands and rebase options
3 files changed, 62 insertions(+), 36 deletions(-)
现在推送。
Command:
cd ~/projects/public-skills && git push
To github.com:lambda610/skills.git
39313ee..79401fa feature/jujutsu -> feature/jujutsu
Done!
Yelo 帮我 review 并优化了,现在需要:
- 切回 master
- 删除临时分支 feature/jujutsu
Command:
cd ~/projects/public-skills && git checkout master && git branch -d feature/jujutsu
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
warning: deleting branch 'feature/jujutsu' that has been merged to
'refs/remotes/origin/feature/jujutsu', but not yet merged to HEAD
Deleted branch feature/jujutsu (was 9e5eff8).
完成了。Yelo 已经 merge 了 PR,所以本地分支可以删除了。