List of jj aliases

14 min read Original article ↗

This page aims to show a list of popular Jujutsu aliases and revset aliases. Each list is backed by a Q/A discussion in the jj project on GitHub, but has no official connection to or endorsement from the JJ project or its maintainers.

⚠️ Note that aliases can be submitted by anyone. Use them at your own risk! Be extra cautious with aliases using "util", "exec" as they can run arbitrary commands on your system.

The list currently contains 26 aliases. Help us by voting on your favorites and adding more in the Github discussion!

VotesAliasDescription
15
  tug /0

Find the closest bookmark in history and advance it forward to closest non-empty commit (using bookmark move)

tug = ["bookmark", "move", "--from", "closest_bookmark(@)", "--to", "closest_pushable(@)"] [revset-aliases] 'closest_bookmark(to)' = 'heads(::to & bookmarks())' 'closest_pushable(to)' = 'heads(::to & ~description(exact:"") & (~empty() | merges()))' [aliases] tug = ["bookmark", "move", "--from", "closest_bookmark(@)", "--to", "closest_pushable(@)"]

Author: glehmann. Snippet updated: 2026-01-06 (edit). Sources: github.com


5
  restack /0

Rebase all my branches/megamerge on trunk().

restack = ["rebase", "-o", "trunk()", "-s", "mutable_roots()"] [revset-aliases] "mutable_roots()" = "roots(trunk()..) & mutable()" [aliases] restack = ["rebase", "-o", "trunk()", "-s", "mutable_roots()"]

Author: Isaac Corbrey. Snippet updated: 2026-02-05 (edit). Sources: github.com


3
  tug /2

Find the closest bookmark in history and advance it forward to closest non-empty commit (using bookmark advance settings)

tug = ["bookmark", "advance"] [revsets] bookmark-advance-to = "closest_pushable(@)" [revset-aliases] 'closest_pushable(to)' = 'heads(::to & ~description(exact:"") & (~empty() | merges()))' [aliases] tug = ["bookmark", "advance"]

Author: glehmann, thomasa88. Deps: jj >= 0.40. Snippet updated: 2026-05-15 (edit). Sources: github.com, github.com


3
  difft

Diff using difftastic (without having it as default)

difft = ["diff", "--tool", "difft"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


2
  chop

Split out a change from the history (evolog) of the current change

chop = ["util", "exec", "--", "bash", "-c", """ set -euo pipefail # Splits the current change at the provided revision from its evolog # # Usage: jj chop <rev> # # The updates after <rev> are put in a new change on top of <rev>. # <rev> keeps its bookmarks original commit ID (useful for shared branches). # # Example: # jj evolog -p # --> Found lvn/2 # jj chop lvn/2 chop = ["util", "exec", "--", "bash", "-c", """ set -euo pipefail START_OP=$(jj op log -n1 -G -T 'id.short()') # FIRST_REV and SECOND_REV will be the final change revisions. # The code never explictly refers to SECOND_REV. # Make sure the provided rev is a commit ID and not a change offset or a # branch name, to protect from changes. FIRST_REV=$(jj log -n1 -G -T "commit_id" -r "$1") FIRST_CHANGE=$(jj log -G -T 'change_id.short()' -r "$FIRST_REV") START_REV="$(jj log -n1 -G -T "commit_id" -r @)" # Create a new change (SECOND_REV) on top of the first revision. The change # will diverge. jj new "$FIRST_REV" -m "Chopped from $FIRST_CHANGE" # Get the contents from the start revision into the change jj restore --from "$START_REV" # Move bookmarks to the first revision jj bookmark move --from "$START_REV" --to "$FIRST_REV" --allow-backwards # Resolve the divergence by dropping the first, left-over, revision. jj abandon "$START_REV" echo "Revision chopped. Undo with: jj op restore $START_OP" """, ""]

Author: thomasa88. Deps: bash. Snippet updated: 2026-06-07 (edit). Sources: discord.com


2
  stage

Put all commits after megamerge into the megamerge

[revset-aliases] "closest_merge(to)" = "heads(::to & merges())" [revset-aliases] "closest_merge(to)" = "heads(::to & merges())" [aliases] stack = ["rebase", "-A", "trunk()", "-B", "closest_merge(@)", "-r"] stage = ["stack", "closest_merge(@)+:: ~ empty()"]

Author: Isaac Corbrey. Snippet updated: 2026-02-03 (edit). Sources: github.com


1
  tug /1

Find the closest bookmark in history and advance it forward to closest non-empty commit (using bookmark advance arguments)

tug = ["bookmark", "advance", "--to", "closest_pushable(@)"] [revset-aliases] 'closest_pushable(to)' = 'heads(::to & ~description(exact:"") & (~empty() | merges()))' [aliases] tug = ["bookmark", "advance", "--to", "closest_pushable(@)"]

Author: glehmann, thomasa88. Deps: jj >= 0.40. Snippet updated: 2026-05-15 (edit). Sources: github.com, github.com


1
  stack <revset>

Put the given revset into the megamerge

[revset-aliases] "closest_merge(to)" = "heads(::to & merges())" [revset-aliases] "closest_merge(to)" = "heads(::to & merges())" [aliases] stack = ["rebase", "-A", "trunk()", "-B", "closest_merge(@)", "-r"]

Author: Isaac Corbrey. Snippet updated: 2026-02-03 (edit). Sources: github.com


1
  bookmark_revs <name>
bookmark_change_ids <name>

List commit/change IDs a local bookmark has had over time

bookmark_revs = ["util", "exec", "--", "bash", "-c", """ ( [aliases] # Get the commit IDs a bookmark has pointed locally to over time # Usage: jj bookmark_revs <bookmark-name> bookmark_revs = ["util", "exec", "--", "bash", "-c", """ ( # Grab the current commit ID in case the bookmark has never been set locally jj log -n1 -G -T "concat(commit_id, '\n')" -r "$1" jj op log -G -T "bookmark_set_revs('$1')" ) | uniq """, ""] # Get the change IDs a bookmark has pointed locally to over time # Usage: jj bookmark_change_ids <bookmark-name> bookmark_change_ids = ["util", "exec", "--", "bash", "-c", """ jj bookmark_revs "$1" | \ while read line; do jj log -n1 -G -T "concat(change_id, '\n')" -r "$line" done | uniq """, ""] [template-aliases] # Get all commit IDs a bookmark has been set to locally over time from the op log. # Note: It will not return any revisions if a bookmark has only been set remotely. # " " around the branch name guarantees exact match. # Matches both `create bookmark BOOKMARK pointing to commit COMMIT` and `point bookmark BOOKMARK to commit COMMIT` 'bookmark_set_revs(name)' = 'if(description.contains(" " ++ name ++ " ") && description.match(glob:"*bookmark*to commit*") != "",concat(description.match(regex:"([0-9a-z]{40})"),"\n"))'

Author: thomasa88. Deps: bash. Snippet updated: 2026-01-17 (edit). Sources: discord.com


1
  restack /1

Rebase all my active branches on trunk (reachable through mutable() from @)

restack = ["rebase", "-o", "trunk()", "-s", "roots(trunk()..) & stack()"] [revset-aliases] 'stack()' = 'stack(@)' 'stack(x)' = 'stack(x, 2)' 'stack(x, n)' = 'ancestors(reachable(x, mutable()), n)' [aliases] restack = ["rebase", "-o", "trunk()", "-s", "roots(trunk()..) & stack()"]

Author: Isaac Corbrey, Austin Seipp. Snippet updated: 2026-01-16 (edit). Sources:


1
  l <revset>

Show log for the given revset

Author: prkl. Snippet updated: 2026-01-09 (edit). Sources: discord.com


1
  plan

Create empty commit with description at the branch tip

plan = ["new", "--no-edit", "heads(@::)", "-m"]

Author: thomasa88. Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  collapse

Collapse the current branch into one commit

collapse = ["squash", "-f", "branch_start(@)+::@", "-t", "branch_start(@)"] [revset-aliases] # From indigo "branch_start(to)" = "heads(::to & trunk())+ & ::to" [aliases] collapse = ["squash", "-f", "branch_start(@)+::@", "-t", "branch_start(@)"]

Author: mrnugget, indigo. Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  issueprefix

Add [ISSUE-<number>] prefix to every non-prefixed commit in the current branch

issueprefix = ["util", "exec", "--", "bash", "-c", """ set -euo pipefail [aliases] issueprefix = ["util", "exec", "--", "bash", "-c", """ set -euo pipefail NUM=$1 PREFIX="[ISSUE-$NUM] " # We don't actually need the editor, since we format the commit using the commit description template, # but we want a command that returns success. export JJ_EDITOR=/usr/bin/true # Change all offending commits at once, to get only one operation in the operation log. jj desc -r "((trunk()..@) | @::) ~ subject(glob:'\\[*')" --config templates.draft_commit_description="concat(\\"$PREFIX\\",coalesce(description, default_commit_description, \\"\n\\"))\" """, ""]

Author: thomasa88. Deps: bash. Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  long

Show detailed log

long = ["log", "-T", "builtin_log_detailed"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  open /0

My branches (heads) that are not yet merged to trunk()

open = ["log", "-r", "heads(mine()) ~ ::trunk()"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  open /1

My commits that are not yet merged to trunk()

open = ["log", "-r", "open()"] [revset-aliases] # stack(x, n) is the set of mutable commits reachable from 'x', with 'n' # parents. 'n' is often useful to customize the display and return set for # certain operations. 'x' can be used to target the set of 'roots' to traverse, # e.g. @ is the current stack. 'stack()' = 'stack(@)' 'stack(x)' = 'stack(x, 2)' 'stack(x, n)' = 'ancestors(reachable(x, mutable()), n)' # The current set of "open" works. It is defined as: all stacks that are # reachable from my working copy, or any other commit I wrote. # n = 1, meaning that nothing from `trunk()` is included, so all resulting # commits are mutable by definition. 'open()' = 'stack(mine() | @, 1) ~ hidden()' [aliases] # Get all open stacks of work open = ["log", "-r", "open()"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  precommit

Manually run pre-commit hooks

precommit = [ "util", precommit = [ "util", "exec", "--", "bash", "-c", "jj diff $1 $2 --name-only --no-pager | xargs pre-commit run --files", "" ]

Author: hdemers. Deps: bash. Snippet updated: 2026-01-07 (edit). Sources: github.com


1
  slice

View the entire branch being worked on in the log

slice = ["log", "-r", "slice()"] [revset-aliases] # View the entire branch being worked on 'slice()' = 'slice(@)' 'slice(from)' = 'ancestors(reachable(from, mutable()), 2)' [aliases] slice = ["log", "-r", "slice()"]

Author: jennings. Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  sync

Fetch from all remotes

sync = ['git', 'fetch', '--all-remotes']

Snippet updated: 2026-01-06 (edit). Sources: github.com


1
  fetch-pr <num>

Fetch PR from origin and create pr-<num> bookmark (using git)

fetch-pr = ['util', 'exec', '--', 'bash', '-c', ''' count=1 fetch-pr = ['util', 'exec', '--', 'bash', '-c', ''' count=1 while true; do git fetch origin pull/$1/head:pr-$1-$count && break ((count++)) done jj git import ''', '']

Author: ase. Deps: bash, git. Snippet updated: 2026-01-17 (edit). Sources: discord.com


1
  rebase-all

Rebase all my branches on trunk()

rebase-all = ["rebase", "-s", "(::trunk())+ & mutable()", "-o", "trunk()"]

Author: steveklabnik. Snippet updated: 2026-01-16 (edit). Sources: lobste.rs


0
  blame

Annotate file with authors. Shorthand for jj file annotate.

blame = ["file", "annotate"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


0
  credit

Annotate file with authors. Shorthand for jj file annotate.

credit = ["file", "annotate"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


0
  short

Show oneline log

long = ["log", "-T", "builtin_log_oneline"]

Snippet updated: 2026-01-06 (edit). Sources: github.com


0
  track-github-PR
untrack-github-PR

fetching and pushing to someone else's PR on Github, with additional remote bookmark to show PR's number (using git, gh)

track-github-PR = ["util", "exec", "--", 'sh', '-euxc', ''' PR=$1 [aliases] track-github-PR = ["util", "exec", "--", 'sh', '-euxc', ''' PR=$1 gh pr view --json headRepository,headRefName,headRepositoryOwner $PR --jq '" set_remote() { jj 2>/dev/null git remote add \"$1\" \"$2\" || jj git remote set-url \"$1\" \"$2\" } set_remote \(.headRepositoryOwner.login) git@github.com:\(.headRepositoryOwner.login)/\(.headRepository.name) jj git fetch --remote \(.headRepositoryOwner.login) --branch \(.headRefName) jj bookmark track \(.headRefName)@\(.headRepositoryOwner.login) origin=$(gh repo view --json owner,name --jq .owner.login) set_remote \"$origin\" \"$(gh repo view --json sshUrl --jq .sshUrl)\" git fetch --force --update-head-ok \"$origin\" \"refs/pull/'"$PR"'/head:refs/remotes/$origin/pull/'"$PR"'\" "' | sh -euxs ''', "jj-track-github-PR"] untrack-github-PR = ["util", "exec", "--", 'sh', '-euxc', ''' PR=$1 gh pr view --json headRepository,headRefName,headRepositoryOwner $PR --jq '" jj bookmark forget \(.headRefName) || true origin=$(gh repo view --json owner,name --jq .owner.login) git for-each-ref --format \"delete %(refname)\" \\ \"refs/remotes/\(.headRepositoryOwner.login)/\(.headRefName)\" \\ \"refs/remotes/$origin/pull/'"$PR"'\" | tee /dev/stderr | git update-ref --stdin "' | sh -euxs ''', "jj-untrack-github-PR"]

Author: ju1m. Deps: sh, gh. Snippet updated: 2026-01-07 (edit). Sources: github.com

The list currently contains 13 revset aliases. Help us by voting on your favorites and adding more in the Github discussion!

VotesRevset AliasDescription
1
  d:x
di

x: diff_lines(substring:x) shorthands

"d:x" = "diff_lines(substring:x)" "di:x" = "diff_lines(substring-i:x)" [revset-aliases] "d:x" = "diff_lines(substring:x)" "di:x" = "diff_lines(substring-i:x)"

Author: dzaima, thomasa88. Snippet updated: 2026-05-28 (edit). Sources: discord.com


1
  merge

The megamerge commit (message = "MERGE")

Author: thomasa88. Snippet updated: 2026-05-04 (edit). Sources:


1
  recent()

Recently created commits (1 month)

'recent()' = 'recent(all())' 'recent(r)' = 'r & committer_date(after:"1 month ago")'

Snippet updated: 2026-01-11 (edit). Sources: zerowidth.com


1
  streams([x])

Find the closest bookmark(s) to (not after 'x').

"streams()" = "heads(::@ & bookmarks())" "streams(x)" = "heads(::x & bookmarks())"

Author: bryce. Snippet updated: 2026-01-11 (edit). Sources: github.com


1
  mine()

Commits are mine if author if either e-mail or name matches, as opposed to only name. Overrides built-in `mine()`.

"mine()" = "author(exact:'My Name') | author(exact:'my.name@email.com')"

Author: bryce. Snippet updated: 2026-01-09 (edit). Sources: github.com


1
  slice([from])

The entire branch being worked on

'slice()' = 'slice(@)' 'slice(from)' = 'ancestors(reachable(from, mutable()), 2)' # View the entire branch being worked on 'slice()' = 'slice(@)' 'slice(from)' = 'ancestors(reachable(from, mutable()), 2)'

Author: jennings. Snippet updated: 2026-01-09 (edit). Sources: github.com


1
  why_immutable(r)

Find what makes revision 'r' immutable

'why_immutable(r)' = "(r & immutable()) | roots(r:: & immutable_heads())"

Author: jennings, hotsphink. Snippet updated: 2026-01-09 (edit). Sources: github.com


1
  closest_bookmark(to)

The closest bookmark(s) to 'to' (not after 'to')

'closest_bookmark(to)' = 'heads(::to & bookmarks())'

Snippet updated: 2026-01-08 (edit). Sources: github.com, discord.com


1
  closest_pushable(to)

The closest pushable commit to 'to' (not after 'to')

'closest_pushable(to)' = 'heads(::to & ~description(exact:"") & (~empty() | merges()))'

Snippet updated: 2026-01-08 (edit). Sources: github.com


1
  stack([x[, n]])

The set of mutable commits reachable from 'x', with 'n' parents.

'stack()' = 'stack(@)' 'stack(x)' = 'stack(x, 2)' # stack(x, n) is the set of mutable commits reachable from 'x', with 'n' # parents. 'n' is often useful to customize the display and return set for # certain operations. 'x' can be used to target the set of 'roots' to traverse, # e.g. @ is the current stack. 'stack()' = 'stack(@)' 'stack(x)' = 'stack(x, 2)' 'stack(x, n)' = 'ancestors(reachable(x, mutable()), n)'

Author: aseipp. Snippet updated: 2026-01-08 (edit). Sources: github.com


1
  tip

The latest commit on the branch. Works with squash workflow. Use: jj new tip

tip = "exactly(heads(@-::~@), 1)"

Author: algmyr. Snippet updated: 2026-01-07 (edit). Sources: discord.com


0
  at

Alternative to '@' in shells that don't support '@'

Author: jennings. Snippet updated: 2026-01-09 (edit). Sources: github.com

To vote for an alias, click on the upvote arrow () next to it. This will take you to the comment on GitHub, where you can vote for the comment using the up arrow button (↑).

If you want to add an alias to a list, please add a comment to the Github discussion of the appropriate list (see below) in the following format:

You can write closely coupled alias together by changing alias_name to alias_name_1 / alias_name_2.

Then add a reply to your own comment with the alias definition in the following format:

Any text you write at the top will be ignored. #### Code ```toml Alias code and any supporting lines here If no supporting lines are needed, you can do this: alias = ["command", "arg1", "arg2"] If supporting lines are needed, do this (section order is not important): [aliases] alias = ["command", "custom_revset"] [revset-aliases] custom_revset = 'heads(::@ & bookmarks())' ``` #### Dependencies Optional. Any extra tools needed for the alias? This includes shells such as Bash or Powershell, as these are not (always) available on all OSes. One entry per line. Bash Github client #### Author Optional. One author per line. Name Name or username #### Source Optional. If the alias was taken from somewhere. Multiple sources can be listed, one per line. https://address.to/source #### Retrieved Optional. When the code snippet was retrieved from the source. If not given, last edit date of the reply will be used. ISO-8601 format. 2026-01-06 #### Changes Optional. You can explain any changes you made compared to a previous reply.

If the alias (source) updates over time, you can add more replies. The last reply with a valid definition will be used in the list.

The Github discussion is checked for updates several times per hour.

If you want to remove an alias from a list, prefer to just mark the alias as "removed" instead of removing the comment. This way we can keep the history of the alias.

#### Remove Reason for the removal.

Is a code snippet on this page outdated? Just click on the date to get to the Github "answer" and add a new reply with the updated info.

If you have a variant that improves the original alias, add a new reply to the alias and it will replace the alias in the list. Depending on the improvement, you might want to list both the old and new authors and sources.

If you have a new completely new variant of an alias or a competing version, just add a new "answer" to the Github discussion and the aliases can "compete" in the list!

The JJ configuration documentation describes how to use aliases. In short, open ~/.config/jj/config.toml and add aliases under [aliases] and revset aliases under [revset-aliases].

You can list your current aliases with jj config list aliases [--include-defaults].