jjq is a lightweight, local merge queue tool for jj (Jujutsu), the Git-compatible VCS.
jjq lets you queue revisions for merging to your trunk branch (eg.,
main bookmark). Each queued item is merged with the current trunk and a
configurable check command is run. If the check passes, the trunk bookmark
advances. If it fails, or there were conflicts with the up-to-date trunk,
the item is marked as failed for you to investigate.
This prevents the "it worked on my branch" problem by ensuring every merge passes checks against the latest trunk.
Prerequisite: make sure jj is installed.
Download the tarball for your platform from the latest release and run the included install script (replace the URL and filename with your platform):
curl -LO https://<releases>/jjq-<version>-<platform>.tar.gz
tar xzf jjq-<version>-<platform>.tar.gz
cd jjq-<version>-<platform>
sudo ./install # installs to /usr/localTo install to a different prefix (no sudo needed):
PREFIX=$HOME/.local ./installSet up jjq in your repository:
jjq initOr non-interactively:
jjq init --trunk main --check "make test"Any revset will do so long as it resolves to a single revision.
jjq push @ # push current revision
jjq push abc # push revision by change IDProcess the next item in the queue:
jjq runDrain the entire queue (continues past failures by default):
jjq run --allStop at the first failure instead:
jjq run --all --stop-on-failurejjq status # overview of queue and recent failures
jjq status --json # machine-readable JSON output
jjq status 42 # detail view of item 42
jjq status 42 --json # detail view as JSON
jjq status --resolve <change_id> # look up item by candidate change IDAfter initialization, change settings with:
jjq config # show all config
jjq config check_command "make test" # set check command
jjq config trunk_bookmark main # set trunk bookmark nameWhen a merge fails, fix the issue and re-push:
jj rebase -b mychange -o main # rebase onto current trunk
# resolve any conflicts
jjq push mychange # clears old failure, re-queuesPush is idempotent: re-pushing the same change ID automatically clears any previous queue or failed entries for that change. Re-pushing the exact same commit ID that is already queued is rejected as a duplicate.
jjq delete 3 # remove item 3 from queue/failed
jjq clean # remove all jjq-run-* workspaces (failed merges)jjq check # run check against current working copy
jjq check --rev main # run check against a specific revision
jjq check -v # show workspace path, shell, and env varsView recent check output (tail the log):
jjq tail # last 20 lines; follows by default
jjq tail --all # from the beginning
jjq tail --no-follow # dump once and exitjjq doctorChecks trunk bookmark, check command, lock state, and workspace preconditions. Catches common config errors before queue items fail.
jjq stores its state in your jj repository using bookmarks and an isolated branch:
- Queue items:
jjq/queue/000001,jjq/queue/000002, ... - Failed items:
jjq/failed/000001, ... - Metadata branch:
jjq/_/_(parented toroot())
To hide jjq metadata from jj log, add this to .jj/repo/config.toml:
[revsets]
log = "~ ::jjq/_/_"(jjq shows this hint on first interactive use)
| Key | Default | Description |
|---|---|---|
trunk_bookmark |
main |
Bookmark pointing to your trunk |
check_command |
(set during init) | Command to run on merge candidates (required before running) |
strategy |
rebase |
Strategy for landing the candidate on trunk (rebase or merge) |