Start with the Hint: at the end of the error. It usually names a command for the problem
jj-stack found.
The examples below use <head-change-id> to identify your stack. If you do not know that ID, run
jj-stack list and copy your stack’s head change ID.
Setup or GitHub access fails
Run the setup checks after cloning a repo, changing its Git remote, or encountering an authentication error:
jj-stack doctor --fix
jj-stack doctor checks your Git remote, GitHub access and push permission, the trunk branch,
and whether GitHub stacked pull requests are available for your repo. With --fix, it also
configures fetches to skip jj-stack’s PR branches and removes leftovers from interrupted commands.
Follow the guidance for any checks that still fail. It does not change GitHub.
The pull requests in a stack are not numbered in ascending order
This is expected. Each GitHub API call takes hundreds of milliseconds, so jj-stack creates
and updates a stack’s PRs concurrently rather than one at a time. GitHub may therefore number a
PR before the PR below it, so PR 42 can end up based on PR 43.
PR numbers never determine the order of a stack. Your local jj history does, and reordering or
inserting changes would change the order of existing PRs anyway.
You want to use the same PRs again after unstack --local
jj-stack unstack --local removes the local links between your changes and their PRs. It leaves
the PRs open on GitHub. If you later want jj-stack submit to update those PRs again, restore
the links with jj-stack relink.
Find the PR numbers on GitHub and the matching change IDs with jj log. For each PR, run:
jj-stack relink <pr> <change-id>
Once you have relinked every PR in the stack, submit from its top change:
jj-stack submit <head-change-id>
jj-stack relink only restores the local link. The later submit updates the existing PRs,
keeping their numbers and discussions. You can use the same steps if you deleted jj-stack’s
local tracking file.
If jj-stack relink reports that the local and GitHub versions differ, choose which work to
keep before retrying.
A PR branch moved outside jj-stack
If someone updates your PR branch from another checkout, your local change may not include
their work. jj-stack submit stops so it does not overwrite that version on GitHub.
Inspect the PR on GitHub, then decide what to do with the work there:
- To keep the work, run
jj-stack checkout --pull-request <pr>. It brings the PR’s commits into your repo. Compare and combine the versions, then runjj-stack submit <head-change-id>. - To replace it with your local version, run
jj-stack relink --replace-remote <pr> <change-id>, thenjj-stack submit <head-change-id>. Here,jj-stack relink --replace-remoteallows the next submit to overwrite the version on GitHub. The submit then pushes your local change to the existing PR.
If GitHub changed the branch while merging or rebasing your stack, run
jj-stack sync <head-change-id> instead. It brings GitHub’s completed merge or rebase into your
local stack.
If someone else pushed to your PR branch and GitHub then merged the PR, what merged came from
their commit, not from the one jj-stack pushed. jj-stack sync cannot tell whether your change is
part of it, so it stops rather than delete your local change. Check the files the PR changed on
GitHub against jj diff -r <change-id>:
- If your change is in them, run
jj abandon <change-id>and thenjj-stack cleanup, which forgets the merged PR’s link. - If it is not, run
jj-stack unstack --local <change-id>to forget the saved links for that local stack, then submit again. The change gets a new pull request.
jj-stack view reports any changes above the merged one as moved; the steps above apply to them.
jj-stack relink reconnects a PR to its original change. Even with --replace-remote, it
cannot transfer the PR to a different change ID.
If you replaced the original change with a new one, run jj-stack checkout --pull-request <pr>
to recover the original change, then move the edits you want to keep onto it.
If the error names a --base parent’s branch, restore that branch to the commit ID in the error
before retrying the child submission. Submitting a child stack does not update its parent.
For a missing branch, either restore it or close and clean up the old PR, then submit again to create a new PR.
A pull request was added to or reordered in the GitHub stack
The local jj history determines PR order. Compare it with the stack on GitHub. If you want the
GitHub order, reproduce it locally with jj, then submit. If you want the local order, run
jj-stack submit <head-change-id> to update the PR bases and GitHub stack.
If the error says the PRs do not identify one GitHub stack, remove the GitHub stack named in the
error with jj-stack unstack --stack <number>, then submit again. This keeps the PRs open.
A stack was removed from the merge queue
If a pull request is removed from the merge queue, GitHub also removes the PRs above
it. jj-stack merge reports GitHub’s reason and links to the checks on the
queue’s temporary merge commit; they do not appear on the PR’s own Checks tab. Fix the failing
check, missing approval, conflict, or repo rule. If GitHub merged any lower PRs, run
jj-stack sync <head-change-id>. Then rerun the same jj-stack merge command.
You merged pull requests on GitHub
After a merge through GitHub or another client, or after a jj-stack merge you left with
--no-wait or Ctrl-C, let GitHub finish, then run jj-stack sync to update your local stack,
refresh the remaining PRs, and remove unused PR branches:
jj-stack sync <head-change-id>
If GitHub also rewrote the remaining PR branches, jj-stack sync handles those rewrites and
keeps any local edits to the remaining changes.
To sync every stack affected by a completed merge, run:
jj-stack sync --all
A blocked stack does not prevent jj-stack from syncing independent stacks. If a selected PR is
still in a merge queue, sync leaves that stack unchanged; rerun jj-stack merge to resume
waiting.
You rebased your stack on GitHub
After GitHub’s Rebase stack action completes, run:
jj-stack sync <head-change-id>
jj-stack sync rebases your original local changes and updates the PR branches with equivalent
commits that retain their jj change IDs. There is no need to relink the PRs. It stops if local
edits or different contents on GitHub prevent it from matching the two versions.
Select this stack explicitly: jj-stack sync --all handles completed merges, not GitHub stack
rebases.
merge did not merge your whole stack
How this can happen: merge selects consecutive open, non-draft PRs from the bottom of your
stack that still match what you submitted. A draft or a changed local commit can limit that
selection. GitHub then accepts or rejects the selected group as a whole. If a check or approval
blocks it, jj-stack does not automatically retry with a smaller group.
Use the reason in the output to choose the next step:
- If your local changes no longer match what you submitted, run
jj-stack submit <head-change-id>, then retryjj-stack merge. - If GitHub reports a pending check, missing approval, draft pull request, repo rule, or
permissions problem, fix that on GitHub, then retry the same
jj-stack mergecommand. - If GitHub reports a conflict, rebase and resolve it with
jj, submit the updated stack, then retryjj-stack merge. - If that pull request was already merged separately, run
jj-stack sync <head-change-id>.
To land a smaller group whose checks and approvals are ready, use
jj-stack merge --pull-request <last-pr-to-merge>.
If all that happened was that trunk advanced, you may not need to rebase. GitHub can merge your stack while its base is behind trunk when it has no conflicts.
GitHub merged your stack, but merge ended with an error
The merge completed, but jj-stack could not finish updating your local stack or cleaning up GitHub. This can happen after a network failure or an interrupted local update. If the local rebase produced conflicts, follow sync conflict recovery. Otherwise, follow the recovery instructions in the error.
Do not retry the merge; the PRs are already merged.
sync rebased your changes into conflicts
If a rebase produces conflicts, jj-stack sync keeps the local rebase but stops before updating
the remaining PRs or cleaning up merged PRs. This can also happen during the automatic sync at
the end of jj-stack merge.
Resolve the conflicts with jj, then run the jj-stack submit command printed in the hint:
jj-stack submit <head-change-id>
Use submit after resolving these conflicts: the local rebase is already applied, so rerunning
sync may find no merged changes left to process.
If unused branches or saved links remain for merged PRs, clean up each by its PR number:
jj-stack cleanup --pull-request <merged-pr>
A command was interrupted
After Ctrl-C, lost connectivity, or a terminal closing mid-command, inspect the current state:
jj-stack view <head-change-id>
If jj-stack submit --edit fails after you edit the pull requests, you can retry without typing
your edits again. jj-stack keeps the file you edited and prints its location after Editor file:
or in the error’s retry command. Use that location in this command:
jj-stack submit <head-change-id> --resume-edit /path/to/saved-editor-file.md
--resume-edit opens your saved edits in the editor again. Use it instead of --edit, which
opens a new file. Include any other options from your original command, such as --base.
See edit every PR at once for more details.
For other interruptions, follow the recovery command in the error. If GitHub completed a merge
but the local update has not finished, run jj-stack sync <head-change-id>. If the local update
is complete, the hint may instead name jj-stack submit to finish updating PRs or
jj-stack cleanup --pull-request <pr> to finish cleanup. Repeating sync may have nothing left
to process.
When no more specific recovery is needed, rerun your original command. jj-stack checks what already succeeded and continues from the current state.
Your old PR branches remain
For merged PRs, run jj-stack sync <head-change-id> first. For closed PRs, or to retry unfinished
cleanup, run:
jj-stack cleanup <head-change-id>
Cleanup keeps a branch while another PR still uses it as its base (an open PR, or a closed PR that GitHub could still reopen), or while an unmerged PR in a GitHub stack needs it. See what to do when cleanup keeps a branch.
“The selector resolved to more than one commit”
Your revset matched several commits, but the command needs one stack head.
Run jj-stack list to identify your intended stack, then rerun your failing command with that
stack’s head change ID.
“Divergent changes are not supported”
Two or more local commits share a change ID. This can happen when separate workspaces modify a
change independently, or when jj-stack checkout --pull-request brings in a PR’s version of a
change you also edited locally. jj-stack cannot choose which version belongs in your stack.
The error’s hint names a jj converge command that combines the versions into one commit. If
you would rather keep one version, show the versions and compare their diffs:
jj log -r 'change_id(<change-id>)'
jj diff -r <first-commit-id>
jj diff -r <second-commit-id>
Keep or combine the edits you need, then abandon the unwanted version by its commit ID. The versions share a change ID, so a bare change ID is ambiguous:
jj abandon <unwanted-commit-id>
Once you’re down to a single commit for that change ID, rerun your jj-stack command.