원클릭으로
jj-git-interactive-rebase-to-jj
Complete reference for translating git interactive rebase operations to Jujutsu equivalents.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Complete reference for translating git interactive rebase operations to Jujutsu equivalents.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | jj-git-interactive-rebase-to-jj |
| description | Complete reference for translating git interactive rebase operations to Jujutsu equivalents. |
| disable-model-invocation | true |
A comprehensive guide for Git users transitioning to Jujutsu, mapping all interactive rebase operations to their jj equivalents and beyond.
Diamond / development-join applicability. The single-chain examples below treat
@as a freely-mutable content commit. That model does not apply inside a development join (the diamond workflow). Inside a join,@is a shared, always-empty[wip]commit sitting directly on a multi-parent join, and that[wip]is the stable coordination surface that makes N concurrent editors safe by construction. In this repo a pushedwipdeploy bookmark additionally tracks@, so machines rebuild from it. Inside a join neverjj describe @, neverjj rebase -r @/--revisions @, and never barejj squash -r @(the form at the squashing example below advances@through a chain and consumes the[wip]). Route changes downward while leaving@empty in place withjj squash --from @ --insert-after <target> -m "..." --keep-emptied [-- <paths>](or--insert-before),jj absorb(documented below as the blame-routed down-route), orjj splitkeeping the wip. Canonical rule, the single-shared-[wip]invariant, and rationale live in~/.claude/skills/jj-version-control/diamond-workflow.md; join mechanics in~/.claude/skills/jj-version-control/SKILL.md; non-interactive command execution in~/.claude/skills/jj-workflow/SKILL.md.
graph TD
A[Start Interactive Rebase] --> B[Edit Todo List]
B --> C[Process Each Commit]
C --> D{Conflict?}
D -->|Yes| E[Stop, Resolve, Continue]
D -->|No| F[Next Commit]
E --> F
F --> G{More Commits?}
G -->|Yes| C
G -->|No| H[Complete Rebase]
In Git, interactive rebase is a batch operation where you:
git rebase -i)--continue, --abort, or --skipgraph TD
A[Identify Target Commit] --> B[Execute Direct Command]
B --> C[Descendants Auto-Rebase]
C --> D[Operation Complete]
D --> E{Want to Undo?}
E -->|Yes| F[jj undo]
E -->|No| G[Continue Working]
F --> A
In Jujutsu, there is no special mode:
The fundamental insight: In jj, every commit operation is non-interactive by default, making "interactive rebase" as a concept obsolete.
| Git Interactive Rebase | What It Does | Jujutsu Command | Key Differences |
|---|---|---|---|
pick <commit> | Keep commit as-is | (automatic) | All commits are "picked" by default; use jj new <commit> to build on top |
reword <commit> | Edit commit message | jj describe -r <commit> -m "message" | Can reword any commit directly without entering special mode |
edit <commit> | Stop to modify commit | jj edit <commit> | Checks out commit immediately; changes automatically amend it |
squash <commit> | Merge into parent (keep both messages) | jj squash -r <commit> | Moves changes from commit into parent; descendants auto-rebase |
fixup <commit> | Merge into parent (discard message) | jj squash -r <commit> | jj doesn't distinguish fixup from squash; both discard the source message by default |
fixup -c <commit> | Merge, use fixup message | jj squash -r <commit> -m "message" | Specify message explicitly with -m |
fixup -C <commit> | Merge, use fixup message, no edit | jj squash -r <commit> | Default behavior when commit has a description |
drop <commit> | Remove commit entirely | jj abandon <commit> | Abandons commit; descendants rebased onto grandparent(s) |
exec <command> | Run shell command at this point | (no direct equivalent) | Use jj log + shell script, or test after each change and jj undo if needed |
break | Pause to make changes | (not needed) | All operations are atomic; never in "rebasing mode" |
label <name> | Mark a point in history | jj bookmark create <name> -r <commit> | Creates a bookmark (jj's term for Git branches) |
reset <label> | Move to labeled point | jj new <bookmark> or jj edit <bookmark> | new creates new commit on top; edit checks out bookmark |
merge <branches> | Create merge commit | jj new <parent1> <parent2> ... | Multiple parents create a merge; supports n-way merges |
| Operation | Git Interactive Rebase | Jujutsu Command | Notes |
|---|---|---|---|
| Reorder commits | Reorder lines in todo list | jj rebase -r <commit> -A <target> or -B <target> | -A = insert after; -B = insert before; descendants follow |
| Split commit | Mark "edit", reset, stage, commit | jj split -r <commit> -- <paths> -m "msg" | Non-interactive: pass explicit paths and -m. Bare jj split (no paths) opens a diff TUI and hangs non-interactive Bash; jj split <paths> opens the editor twice (extracted commit plus remainder), so pre-stage the remainder via jj describe -r <commit> -m "<remainder>" first. See jj-workflow "Non-interactive command execution". |
| Partial squash | Stage subset, commit --amend | jj squash -i -r <commit> | Interactive diff editor to select hunks to move |
| Move to specific ancestor | fixup + reorder + exec | jj squash --from <commit> --into <ancestor> | Can target any ancestor, not just parent |
| Move between any commits | (not possible) | jj squash --from <src> --into <dest> | Works on any two commits in history |
| Edit without checkout | (not possible) | jj diffedit -r <commit> | Edit commit's diff directly in editor without checking out |
| Auto-absorb changes | (not possible) | jj absorb | Automatically distributes working copy changes to appropriate ancestors |
| Keep empty after squash | (not possible) | jj squash --keep-emptied | Preserves source commit after moving changes |
| Git Interactive Rebase | Jujutsu Equivalent |
|---|---|
| Rebase stops with conflict markers | Conflict is committed; marked as "conflict" in log |
git add <file> | (automatic - jj tracks all files) |
git rebase --continue | (not needed - never in special mode) |
git rebase --abort | jj undo or jj op restore <operation> |
git rebase --skip | jj abandon <commit> (to skip applying a commit) |
| Resolve before continuing | jj new <conflicted>, resolve, jj squash into conflicted commit |
git mergetool | jj resolve (launches merge tool for each conflict) |
Git Interactive Rebase:
sequenceDiagram
participant U as User
participant G as Git
participant E as Editor
U->>G: git rebase -i HEAD~5
G->>E: Open todo list editor
E->>U: Show:<br/>pick A<br/>pick B<br/>pick C
U->>E: Edit to:<br/>pick A<br/>pick C<br/>pick B
E->>G: Save and close
G->>G: Execute rebase
G->>U: Complete (or stop on conflict)
Jujutsu Direct Command:
sequenceDiagram
participant U as User
participant J as Jujutsu
U->>J: jj rebase -r C -B B
J->>J: Move C before B
J->>J: Auto-rebase descendants
J->>U: Complete immediately
Git:
A - B - C - D - E (HEAD)
Goal: Combine C, D, E into one commit
git rebase -i HEAD~5
# Change todo list:
pick A
pick B
pick C
squash D
squash E
Jujutsu:
A - B - C - D - E (@)
Goal: Same
jj squash -r @ # E squashed into D, @ now points to D
jj squash -r @ # D squashed into C, @ now points to C
# Result: A - B - C (@)
Single-chain cleanup only. In a development join
@is the shared empty[wip]sitting on the multi-parent join, sojj squash -r @would consume that[wip]into its parent and re-point@— emptying the editing surface concurrent actors write to and, in this repo, dragging the pushedwipdeploy bookmark. There, route changes downward withjj squash --from @ --insert-before <target> --keep-emptied -m "..."(or--insert-after <target>), which leaves@empty and in place, orjj absorb. See~/.claude/skills/jj-version-control/diamond-workflow.md.
Or more directly:
# From E, squash everything into C
jj squash --from @ --into C
jj squash --from @- --into C
These features have no equivalent in Git's interactive rebase and represent jj's advanced capabilities.
What Git has:
git reflog)What Jujutsu has:
jj op log # See all operations performed on repository
jj op show <id> # Show what an operation changed
jj undo # Undo last operation (any operation!)
jj op restore <id> # Restore repo to any previous state
Example:
$ jj log -r @
@ abc123 feat: add feature X
$ jj describe -m "feat: add feature Y" # Oops, wrong message
$ jj squash # Oops, didn't mean to squash
$ jj rebase -d main # Oops, wrong base
$ jj op log
@ def456 ... rebase
○ ghi789 ... squash
○ jkl012 ... describe
○ mno345 ... [original state]
$ jj undo # Undoes rebase
$ jj undo # Undoes squash
$ jj undo # Undoes describe - back to original!
Git limitation: Can only edit one commit at a time in interactive rebase mode.
Jujutsu capability: Edit multiple commits in parallel:
# Reword multiple commits simultaneously
jj describe -r A -m "Fix typo in A"
jj describe -r B -m "Fix typo in B"
jj describe -r C -m "Fix typo in C"
# Split multiple commits (non-interactive: pre-stage the remainder, then split by paths)
jj describe -r X -m "<remainder>"
jj split -r X -- <paths> -m "<extracted>"
jj describe -r Y -m "<remainder>"
jj split -r Y -- <paths> -m "<extracted>"
# Note: `-i` and parameterless `jj split` open an interactive TUI and hang non-interactive shells.
# Diamond note: splitting while keeping the empty `[wip]` at `@` is a valid down-route, but never `jj describe @` and never `jj rebase -r @`.
# All operations execute immediately and independently
# Make changes to multiple files
echo "fix" >> file1.txt
echo "improvement" >> file2.txt
echo "refactor" >> file3.txt
# Automatically move each change to the commit that last touched those lines
jj absorb
# jj analyzes blame information and distributes changes appropriately
Visual representation:
graph LR
A[Working Copy<br/>Changes to<br/>file1, file2, file3] -->|jj absorb| B[Changes<br/>distributed<br/>automatically]
B --> C[Commit X<br/>gets file1 changes]
B --> D[Commit Y<br/>gets file2 changes]
B --> E[Commit Z<br/>gets file3 changes]
The working copy is always a commit:
jj log
@ work-in-progress # Working copy is always a commit
○ finished-feature
○ main
# No "git add" needed - all changes are tracked
# No "git commit --amend" needed - changes automatically amend @
# No "git stash" needed - just create new commit with jj new
# After a rebase that would conflict in Git:
jj log
@ abc123 (conflict) attempted merge
○ def456 feature branch
○ ghi789 main
# Work continues normally - conflict is just marked
jj new # Create new commit on top of conflict
jj new other-commit # Or work on something else
jj edit abc123 # Come back to resolve conflict later
# Move changes between ANY two commits (not just parent/child)
jj squash --from <commit-A> --into <commit-B>
# Insert commit anywhere in history
jj rebase -r X -A Y -B Z # Insert X after Y and before Z
# Duplicate commits to multiple locations
jj duplicate <commit> -d <dest1>
jj duplicate <commit> -d <dest2>
# Select multiple commits with expressions
jj rebase -s 'author("alice")' -d main # All commits by Alice
jj abandon 'empty()' # All empty commits
jj squash -r 'description(glob:"WIP:*")' # All WIP commits
jj log -r 'mine() & ~bookmarks()' # My commits not on bookmarks
Track how a single change evolved:
jj evolog -r <commit> # See all versions of this commit
jj evolog -p # With diffs showing what changed each time
# Shows history of amendments, rebases, descriptions, etc.
Scenario: You have 10 commits with several "WIP" commits, typo fixes, and changes that should be reordered.
Git approach:
git rebase -i main
# Manually edit todo list:
# - Reorder commits
# - Mark several commits as "fixup"
# - Mark one as "edit" to split
# Deal with conflicts at each step
git rebase --continue (multiple times)
Jujutsu approach:
# Reword WIP commits
jj describe -r <commit1> -m "proper message"
jj describe -r <commit2> -m "another proper message"
# Squash fixup commits
jj squash -r <fixup-commit1>
jj squash -r <fixup-commit2>
# Reorder if needed
jj rebase -r X -B Y
# Split a commit (non-interactive: pre-stage the remainder, then split by paths)
jj describe -r <large-commit> -m "<remainder>"
jj split -r <large-commit> -- <paths> -m "<extracted>"
# All done! Each command executes immediately
# Use jj undo at any point if you make a mistake
Git approach:
# Make fix
git add <files>
git commit --fixup=<commit-to-fix>
git rebase -i --autosquash <base>
# Interactive rebase executes
Jujutsu approach:
# Approach 1: Direct edit
jj edit <commit-to-fix>
# Make changes
# Changes automatically amend the commit
jj new @- # Return to where you were
# Approach 2: From working copy
# Make changes in working copy
jj squash --into <commit-to-fix>
# Approach 3: Interactive selection
jj squash -i --into <commit-to-fix>
Scenario:
C - D - E (feature-v2)
/
B (feature-v1)
/
A (main)
Want to rebase feature-v2 directly onto A
Git approach:
git rebase --onto A B feature-v2
# OR
git rebase -i A
# Manually drop commits from feature-v1
Jujutsu approach:
# Approach 1: Direct rebase
jj rebase -s C -d A
# Approach 2: Using revset
jj rebase -s 'B..feature-v2' -d A
# Result:
# A - C' - D' - E' (feature-v2)
# \
# B (feature-v1)
Scenario: You ran several operations and realized the third operation was wrong.
Git approach:
# Very difficult without reflog expertise
git reflog
git reset --hard HEAD@{5} # Hope you count correctly
# Lost all subsequent work
Jujutsu approach:
jj op log
# @ op4 ... latest operation
# ○ op3 ... the mistaken operation
# ○ op2 ...
# ○ op1 ...
jj undo # Undoes op4
jj undo # Undoes op3 (the mistake)
jj op restore op4 # Restores op4
# Now have: op1, op2, op4 (op3 was removed)
# Or restore to exact state:
jj op restore <op-before-mistake>
Git approach:
git rebase -i <commit>^
# Mark commit as "edit"
git reset HEAD^
git add file1.txt
git commit -m "Part 1"
git add file2.txt
git commit -m "Part 2"
git rebase --continue
Jujutsu approach:
# By path specification (non-interactive: pre-stage the remainder, then split by paths):
jj describe -r <commit> -m "Part 2"
jj split -r <commit> -- file1.txt -m "Part 1"
# file1.txt goes to the first commit; file2.txt stays in the second commit
# Note: `-i` and parameterless `jj split` open an interactive TUI and hang non-interactive shells; always split by explicit paths with `-m`, pre-staging the remainder description.
| Task | Jujutsu Command |
|---|---|
| Change commit message | jj describe -r <commit> -m "message" |
| Open editor for message | jj describe -r <commit> |
| Change author | jj describe -r <commit> --author "Name <email>" |
| Reset author to self | jj describe -r <commit> --reset-author |
| Task | Jujutsu Command |
|---|---|
| Squash into parent | jj squash -r <commit> |
| Squash partial into parent | jj squash -i -r <commit> |
| Squash into specific ancestor | jj squash --from <commit> --into <ancestor> |
| Squash between any commits | jj squash --from <src> --into <dest> |
| Keep empty after squash | jj squash -r <commit> --keep-emptied |
| Auto-squash to right places | jj absorb |
| Task | Jujutsu Command |
|---|---|
| Split commit (non-interactive) | jj split -r <commit> -- <paths> -m "msg" (pre-stage remainder with jj describe -r <commit> -m; bare jj split / -i open a TUI and hang non-interactive shells) |
| Split by paths | jj split -r <commit> <paths> |
| Create new commit on top | jj new <commit> |
| Move working copy changes to new commit | jj commit |
| Move specific paths to new commit | jj commit <paths> |
| Task | Jujutsu Command |
|---|---|
| Remove commit | jj abandon <commit> |
| Edit commit directly | jj edit <commit> |
| Edit commit without checkout | jj diffedit -r <commit> |
| Duplicate commit | jj duplicate <commit> |
| Duplicate to specific location | jj duplicate <commit> -d <dest> |
Inside a development join: keep @ as the empty [wip] | Do not describe @ / rebase -r @ / bare squash -r @; route down with jj squash --from @ --insert-after <target> -m "..." --keep-emptied, jj absorb, or jj split (keep wip). See ~/.claude/skills/jj-version-control/diamond-workflow.md. |
| Task | Jujutsu Command |
|---|---|
| Move commit after target | jj rebase -r <commit> -A <target> |
| Move commit before target | jj rebase -r <commit> -B <target> |
| Move commit to new parent | jj rebase -r <commit> -d <parent> |
| Move commit tree | jj rebase -s <commit> -d <dest> |
| Move branch to new base | jj rebase -b <branch> -d <dest> |
| Task | Jujutsu Command |
|---|---|
| See conflicted files | jj status or jj log -r 'conflict()' |
| Start resolving conflicts | jj new <conflicted-commit> |
| Resolve with merge tool | jj resolve |
| List conflicts | jj resolve --list |
| Move resolution into conflicted commit | jj squash |
| Task | Jujutsu Command |
|---|---|
| Undo last operation | jj undo |
| See operation history | jj op log |
| Restore to specific operation | jj op restore <operation> |
| View changes in operation | jj op show <operation> |
| Create reverse commit (git revert) | jj revert -r <commit> -d <target> |
jj edit X # Checkout X, changes amend it
# ... make changes ...
# Changes automatically amend X
# Make changes in working copy
jj squash --into X
# Non-interactive: pre-stage the remainder, then split by paths.
jj describe -r X -m "<remainder>"
jj split -r X -- <paths> -m "<extracted>"
# `-i` and parameterless `jj split` open an interactive TUI and hang non-interactive shells.
jj squash -r C # C → B
jj squash -r B # B → A
# Result: One commit at A with all changes
jj rebase -r C -B B
jj rebase -r X -d <other-branch>
jj undo # Undo last operation
jj undo # Undo one more
jj op restore <operation-id> # Go back to specific state
jj rebase flags| Flag | Meaning | Example |
|---|---|---|
-r <revset> | Rebase only specified commits | jj rebase -r X -d Y |
-s <revset> | Rebase commit and descendants | jj rebase -s X -d Y |
-b <revset> | Rebase branch (revs from base) | jj rebase -b X -d Y |
-d <revset> | Destination (new parent) | jj rebase -r X -d Y |
-A <revset> | Insert after (and rebase children) | jj rebase -r X -A Y |
-B <revset> | Insert before (and rebase children) | jj rebase -r X -B Y |
jj squash flags| Flag | Meaning | Example |
|---|---|---|
-r <revset> | Squash this commit into parent | jj squash -r X |
--from <revset> | Source of changes | jj squash --from X --into Y |
--into <revset> | Destination of changes | jj squash --into Y |
-i | Interactive (select hunks) | jj squash -i -r X |
-m <message> | Set description | jj squash -r X -m "msg" |
--keep-emptied | Keep empty source commit | jj squash -r X --keep-emptied |
<paths> | Squash only these paths | jj squash file1.txt file2.txt |
jj new flags| Flag | Meaning | Example |
|---|---|---|
<revset> | Parent(s) of new commit | jj new X or jj new X Y (merge) |
-m <message> | Set description | jj new X -m "Start feature" |
-A <revset> | Insert after | jj new -A X |
-B <revset> | Insert before | jj new -B X |
--no-edit | Don't edit new commit | jj new X --no-edit |
Git's interactive rebase exists because:
Jujutsu eliminates these needs by:
@)The result: Every operation you'd use interactive rebase for in Git is a direct, immediate command in jj. You never enter a special mode, never need to continue or abort, and can undo anything instantly.
This document serves as a complete reference for transitioning from Git's interactive rebase to Jujutsu's direct commit editing model.
Index curated reference corpora into a searchable knowledge graph via the cognee engine, then query it to ground technical writing, review, and analysis. Use when ingesting reference documents into named datasets or retrieving grounding context for tasks like drafting or reviewing a manuscript. A reference-knowledge index, explicitly not agent session memory.
Nix development conventions for flakes, derivations, modules, and code style. Use when authoring flake.nix files, writing derivations or builders, designing NixOS/nix-darwin/home-manager modules, or following nix formatting and naming conventions. For check architecture and CI integration, see preferences-nix-checks-architecture and preferences-nix-ci-cd-integration.
Approximately-verifiable, refinement-driven development for type-driven domain-driven design. Use when modeling a domain as a dependently-typed Lean 4 specification, refining/lowering it to a Rust implementation, lifting the implementation back via Charon and Aeneas to check spec<->implementation correspondence (translation validation) — mechanically when tractable, otherwise via differential testing or LLM comparison — or when generating and diffing type-system diagrams of the model and implementation to track their evolution. Mechanical on-the-nose proof is the precise ideal, not a requirement; its absence is not a failure of the method.
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
Algebraic data type patterns including sum types, product types, and pattern matching across languages. Load when designing type hierarchies or working with discriminated unions.
Algebraic laws including functor/monad laws and property-based testing strategies. Load when verifying algebraic properties or writing property tests.