Skip to main content
muloka

commit-commands-jj

by muloka

Commands for jj (Jujutsu) commit workflows including commit, push, and PR creation

Installation guide →
10 commandsproductivity GitHub

Commands

abandon

Discard a jj change (current or specified revision)

clean_stale

Cleans up stale bookmarks and workspaces in a jj repository by fetching latest remote state and removing bookmarks deleted on the remote.

commit-push-pr

Commit, push, and open a PR using jj

commit

Finalize the current jj change with a description

describe

Set or update the description of the current jj change

edit

Edit an earlier jj change by moving the working copy to it

new

Start a new jj change on top of the current one (or a specified revision)

squash

Squash the current jj change into its parent

sync

Fetch from remote and rebase the current change onto trunk

undo

Undo the last jj operation

Documentation

# Commit Commands Plugin (jj)

Streamline your jj (Jujutsu) workflow with simple commands for committing, navigating changes, syncing with trunk, and creating pull requests.

## Overview

The Commit Commands Plugin for jj automates common Jujutsu operations, reducing context switching and manual command execution. Instead of running multiple jj commands, use a single slash command to handle your entire workflow.

**Key difference from Git**: In jj, the working copy IS already a commit. There is no staging area. All changes are automatically tracked. The `/commit` command finalizes the current change with a description and starts a new empty change on top.

## Setup

### Colocated repos (`.jj/` + `.git/`)

If you initialized with `jj git clone` or `jj git init --colocate`, everything works out of the box — including `gh` CLI for PR creation.

### Non-colocated repos (`.jj/` only)

For `/commit-push-pr`, the `gh` CLI needs access to Git state. Either:

1. **Set `GIT_DIR`** before running:
   ```bash
   export GIT_DIR=.jj/repo/store/git
   ```

2. **Or run `jj git export`** before using `gh` commands to sync jj state to the backing Git repo.

## Commands

### `/commit`

Finalizes the current jj change with an automatically generated description.

**What it does:**
1. Reviews the current jj status and diff
2. Examines recent change descriptions to match your repository's style
3. Runs `jj commit -m "<msg>"` to describe the current change and start a new empty one

**Usage:**
```bash
/commit
```

**Example workflow:**
```bash
# Make some changes to your code
# (jj automatically tracks everything — no staging needed)
# Then simply run:
/commit

# Claude will:
# - Review your changes via jj diff
# - Create a commit with an appropriate description
# - A new empty change is created on top
```

**Features:**
- Automatically drafts descriptions that match your repo's style
- No staging step — all working copy changes are included
- For partial commits, use `jj split` before running `/commit`

### `/commit-push-pr`

Complete workflow command that commits, pushes, and creates a pull request in one step.

**What it does:**
1. Finalizes the working copy with `jj commit -m "<msg>"`
2. Checks if the change is on trunk and needs a bookmark
3. Creates a bookmark on the committed change if needed
4. Pushes the bookmark with `jj git push`
5. Creates a pull request using `gh pr create`

**Usage:**
```bash
/commit-push-pr
```

**Example workflow:**
```bash
# Make your changes
# Then run:
/commit-push-pr

# Claude will:
# - Finalize your change with a description
# - Create a bookmark (jj's equivalent of a branch name)
# - Push to remote
# - Open a PR with summary and test plan
# - Give you the PR URL to review
```

**Features:**
- Uses jj revsets (`trunk()`) for idiomatic trunk detection
- Creates bookmarks automatically when needed
- Works with colocated repos out of the box
- For non-colocated repos, provides guidance on `GIT_DIR` setup

**Requirements:**
- GitHub CLI (`gh`) must be installed and authenticated
- Repository must have a remote configured

### `/describe`

Sets or updates the description of the current jj change without finalizing it.

**What it does:**
1. Reviews the current jj status and diff
2. Runs `jj describe -m "<msg>"` to set a description on the current change
3. The change ID stays the same — you remain on the same change

**Usage:**
```bash
/describe
```

**Example workflow:**
```bash
# Start working on something
# Label what you're doing:
/describe

# Claude will:
# - Review your current changes
# - Set an appropriate description
# - You stay on the same change (unlike /commit)
```

**Features:**
- Does NOT finalize the change or start a new one (unlike `/commit`)
- Useful for labeling work-in-progress changes
- Identifies changes in anonymous branches (jj favors descriptions over bookmarks)
- Update the message before pushing

### `/new`

Starts a new empty change on top of the current one (or a specified revision).

**What it does:**
1. Runs `jj new` to create a new empty change
2. Optionally sets a description if you state your intent
3. Confirms the new change with `jj log`

**Usage:**
```bash
/new
/new main    # start on top of main
```

**Example workflow:**
```bash
# After finishing work on a change:
/new

# Claude will:
# - Create a new empty change on top
# - Optionally describe it if you said what you're working on next
# - Show the new change
```

**Features:**
- No need to commit first — jj auto-snapshots the working copy
- Accepts an optional target revision to start from a different point
- The previous change keeps all its content

### `/edit`

Moves the working copy to an earlier change so you can amend it in place.

**What it does:**
1. Runs `jj edit <revision>` to switch to the target change
2. Shows the status and diff of the change
3. Reminds you to run `/new` when done

**Usage:**
```bash
/edit <revision>
```

**Example workflow:**
```bash
# Need to fix something in a previous change:
/edit qpvuntsm

# Claude will:
# - Switch the working copy to that change
# - Show what's in the change
# - Remind you to /new when done
```

**Features:**
- Amends the target change in place — no cherry-picking needed
- Descendants are automatically rebased
- Does NOT auto-return to the tip — you control when you're done

### `/sync`

Fetches the latest remote state and rebases your current work onto trunk.

**What it does:**
1. Runs `jj git fetch` to get the latest remote state
2. Rebases onto `main@origin` (falls back to `trunk()`)
3. Checks for conflicts with `jj log -r 'conflicts()'`
4. Shows the final state with `jj log`

**Usage:**
```bash
/sync
```

**Example workflow:**
```bash
# Before starting work or before pushing:
/sync

# Claude will:
# - Fetch from remote
# - Rebase onto trunk
# - Report any conflicts or confirm success
# - Show the updated log
```

**Features:**
- Equivalent of `git pull --rebase` in a single command
- Auto-prunes deleted remote tracking refs
- Reports conflicts clearly (jj records conflicts in commits, not the working copy)

### `/squash`

Squashes the current change into its parent, combining their content and descriptions.

**What it does:**
1. Checks if the current change has modifications
2. Runs `jj squash` to move changes into the parent
3. Cleans up the combined description if needed
4. Shows the result

**Usage:**
```bash
/squash
/squash --into <rev>    # squash into a specific change
```

**Example workflow:**
```bash
# After making a small fixup:
/squash

# Claude will:
# - Move your changes into the parent change
# - Clean up the description if the merge was awkward
# - Show the final state
```

**Features:**
- Idiomatic way to fold fixups into a previous change
- Reports "nothing to squash" if the current change is empty
- Supports `--into <rev>` for squashing into a non-parent change
- Automatically cleans up combined descriptions

### `/undo`

Undoes the last jj operation by restoring the repository to its previous state.

**What it does:**
1. Reviews the operation log to identify the last operation
2. Runs `jj undo` to reverse it
3. Confirms the result and reports what was undone

**Usage:**
```bash
/undo
```

**Example workflow:**
```bash
# After an accidental squash or abandon:
/undo

# Claude will:
# - Show the last operation
# - Reverse it
# - Confirm the repository state
```

**Features:**
- Every jj operation is recorded — nothing is truly lost
- Undo itself is an operation and can be undone
- For older operations, use `jj op restore <op-id>` (op IDs shown in `jj op log`)
- Much safer than git's reflog-based recovery

### `/abandon`

Discards a jj change entirely, rebasing descendants onto its parent.

**What it does:**
1. Warns if the change has modifications that will be lost
2. Runs `jj abandon` to discard the change
3. Shows the result and reminds you about `/undo`

**Usage:**
```bash
/abandon
/abandon <revision>    # abandon a specific change
```

**Example workflow:**
```bash
# Discard a change you no longer need:
/abandon

# Claude will:
# - Warn if the change has content
# - Abandon it
# - Show the updated log
# - Remind you about /undo for recovery
```

**Features:**
- Descendants are rebased onto the abandoned change's parent
- Abandoning the working copy (`@`) auto-creates a new empty change
- Recoverable with `/undo` — nothing is permanently lost
- Accepts a revset for abandoning multiple changes

### `/clean_stale`

Cleans up stale local bookmarks and workspaces (replaces `/clean_gone` from the Git plugin).

**What it does:**
1. Fetches latest remote state with `jj git fetch`
2. Lists all bookmarks to find those deleted on the remote
3. Lists workspaces to find stale ones
4. Deletes stale bookmarks with `jj bookmark delete`
5. Forgets stale workspaces with `jj workspace forget`

**Usage:**
```bash
/clean_stale
```

**Example workflow:**
```bash
# After PRs are merged and remote bookmarks are deleted
/clean_stale

# Claude will:
# - Fetch latest remote state
# - Find bookmarks deleted on remote
# - Remove stale bookmarks and workspaces
# - Report what was cleaned up
```

**Features:**
- jj auto-prunes remote tracking refs during fetch (no `--prune` needed)
- Handles both bookmarks and workspaces
- Reports if no cleanup was needed

**When to use:**
- After merging and deleting remote branches/bookmarks
- When your bookmark list is cluttered with stale entries
- During regular repository maintenance

## Installation

```bash
claude plugins add ./plugins/commit-commands-jj
```

## Best Practices

### Using `/commit`
- Let Claude review your changes and match your repo's description style
- For partial commits, use `jj split` first, then `/commit`
- Use for routine commits during development

### Using `/describe`
- Use to label work-in-progress changes before they're ready to commit
- Prefer descriptions over bookmarks for identifying changes (idiomatic jj)
- Update descriptions before pushing to ensure clean history

### Using `/commit-push-pr`
- Use when you're ready to create a PR
- Ensure all your changes are complete and tested
- Review the PR description and edit if needed

### Using `/new`
- Run after `/commit` to start fresh work
- Use `/new <rev>` to branch from a specific change
- Combine with `/describe` to label what you're about to work on

### Using `/edit`
- Use to amend earlier changes without cherry-picking
- Always run `/new` when done to return to the tip
- Descendants are rebased automatically — check for conflicts after editing

### Using `/sync`
- Run before starting new work to stay up to date
- Run before pushing to avoid conflicts
- If conflicts are reported, resolve them before continuing

### Using `/squash`
- Use to fold small fixups into the parent change
- Check the combined description after squashing
- For squashing into non-parent changes, specify `--into <rev>`

### Using `/undo`
- Safe to run — the undo itself can be undone
- Check `jj op log` to understand what will be reversed
- For older operations, use `jj op restore <op-id>` directly

### Using `/abandon`
- Always check the diff before abandoning — modifications will be lost
- Use `/undo` immediately if you abandoned by mistake
- Descendants are rebased onto the parent, not deleted

### Using `/clean_stale`
- Run periodically to keep your bookmark list clean
- Especially useful after merging multiple PRs
- Safe to run — only removes bookmarks already deleted remotely

## jj Concepts for Git Users

| Git | jj |
|---|---|
| staging area | No equivalent — working copy IS a commit |
| `git add` | Not needed — all changes automatically tracked |
| `git commit` | `jj commit` — finalizes current change, starts new one |
| `git commit --amend` | `jj describe` or `jj squash` |
| `git checkout -b` | `jj new` — start a new change |
| `git checkout <commit>` | `jj edit` — move working copy to a change |
| `git pull --rebase` | `jj git fetch` + `jj rebase` |
| `git rebase -i` (squash) | `jj squash` |
| `git reset HEAD~1` | `jj undo` |
| `git reflog` | `jj op log` |
| branch | bookmark |
| `git branch` | `jj bookmark` |
| `git push` | `jj git push` |
| `git fetch --prune` | `jj git fetch` (auto-prunes) |
| `[gone]` branches | Bookmarks deleted on remote |
| worktree | workspace |

## Requirements

- jj (Jujutsu) must be installed and configured
- For `/commit-push-pr`: GitHub CLI (`gh`) must be installed and authenticated
- Repository must be a jj repository with a remote

## Author

[muloka](https://github.com/muloka)

## Version

1.0.0