Skip to content

Pull requests

This page is the how-to. Why stacks retarget themselves, how review threads follow a force-push, and how the merge queue decides what to test are explained in Code review. Every neo pr flag is listed in the neo pr reference.

All neo pr commands take an optional <owner>/<repo> (or bare <repo>) after their arguments. Inside a checkout whose remote points at this host you can leave it out.

Push your branch first. The push output links straight to the form:

Create a pull request for 'fix-login' on neosource by visiting:
https://neosource.dev/acme/api/pulls/new?compare=fix-login

Or open Pull requests → New pull request in the repository. Pick a Base branch (the default branch is preselected) and a Compare branch, check the Files changed tab, give it a title and a Markdown description, and press Create pull request. The diff is taken from the merge base, so it is the same change the merge would apply.

If the branch already has an open pull request, the push output links to it instead.

Terminal window
neo pr create --title "Reject expired session cookies" --body "Closes #412"

The source branch defaults to your current git branch (--head overrides it) and the base defaults to the repository’s default branch (--base overrides it). Without --title, the oldest commit subject on the branch is used.

A Closes #N line in the description links the issue, and the issue closes when the pull request merges. neo pr edit <n> --body-file - replaces the description from stdin and re-reads those links.

A draft is open and visible, but it cannot be merged or queued: the merge gate reports “is a draft — mark it ready for review first”.

Terminal window
neo pr create --draft
neo pr ready 42 # mark it ready for review
neo pr ready 42 --undo # back to a draft

On the web, tick Create as draft on the new pull request form. On a draft’s page the merge box offers Ready for review in place of Merge, and someone with write access can turn an open pull request back into a draft with Convert to draft.

To stack, open a pull request whose base is the branch of another open pull request in the same repository. There is no separate “stack” step: the new pull request becomes the child of the open one whose source branch it targets.

Terminal window
git switch -c refactor-auth main
# …commit, push…
neo pr create --title "Extract the session store"
git switch -c expiry-check refactor-auth
# …commit, push…
neo pr create --base refactor-auth --title "Reject expired session cookies"

Each pull request in the stack shows only its own diff, and the Stack panel in its sidebar lists every pull request in the stack with its state. When the bottom one merges, the next one is retargeted onto its base automatically (Code review explains how).

A pull request with stacked children cannot be squash-merged. Merge it with a merge commit, or land the stack from the top down.

Open the Files changed tab to read the diff and leave inline comments; the Conversation tab holds the description, comments, review threads and the activity history.

To submit a review in the web UI, press Review in the Reviewers panel in the sidebar, add an optional summary, then press Comment, Request changes or Approve: each one submits straight away. From the command line:

Terminal window
neo pr review 42 --approve --body "Looks right; the expiry test covers it."
neo pr review 42 --request-changes --body "This drops the clock-skew allowance."
neo pr comment 42 --body "Rebased on main, ready again."

How reviews affect merging:

  • A pull request whose branch protection requires approvals shows “N of M required approving review(s)” until enough reviewers approve. The author’s own approval never counts.
  • An outstanding Request changes blocks the merge: “a reviewer has requested changes”.
  • Approving can complete the merge: if auto-merge is armed and the approval was the last missing requirement, the pull request merges at once.

Pull requests waiting on your review are listed under Review requested on /reviews. To ask someone, use Request a review in the pull request’s Reviewers panel, which repository writers and the pull request’s author see; the same panel withdraws a request. You cannot request a review from yourself. The reviewer is notified only if they can read the repository. Submitting a review fulfils your request.

The merge box at the top of the Conversation tab says whether the pull request can merge, and lists every requirement that is still open: required checks with their state, approvals, unresolved review threads, and whether the branch is behind its target. Each check links to its row on the Checks tab.

What is required comes from the target branch’s protection rule, under Settings → Branches (admins only). A branch with no matching rule has no gate. The rule semantics are in Code review.

When the branch is behind and the rule requires it to be up to date, press Update branch, or:

Terminal window
neo pr update-branch 42

This merges the target into your branch as a merge commit; it never rebases, so your commits and review threads keep their anchors. An armed auto-merge stays armed. It is refused when the merge would conflict, when the source branch lives in a fork, or when someone pushed to the branch since you last looked.

From a terminal, wait for the checks instead of polling:

Terminal window
neo pr wait 42 # until the checks that gate the PR finish
neo pr wait 42 --for merged # until it lands, including queue verification

neo pr wait exits 0 when the condition held and with a distinct code for each other outcome: 3 a check failed, 4 closed without merging, 5 rejected by the queue or still refused by the gate, 6 timed out. The full list is in the reference.

A repository allows merge (a two-parent merge commit), squash (one commit carrying the whole change, with Co-authored-by: trailers for everyone else on the branch), or both. Which ones, and the default, are set under Settings → General → Merge methods. When more than one is allowed, the merge box shows a picker beside Merge; on the command line pass --merge or --squash, or neither for the repository’s default. A method the repository does not allow is refused, not swapped for another.

Merge in the web UI and neo pr merge are the same action. Every merge goes through the target branch’s merge queue:

  • a pull request whose requirements pass, whose branch is current and whose queue is empty merges right away;
  • otherwise it is queued, and the merge box shows its progress (Queued, then testing against the latest target, then merging). It stays open until the tested change has merged.
Terminal window
neo pr merge 42 # merge now, or queue it
neo pr merge 42 --squash
neo pr merge 42 --auto # arm it to merge when it is ready

A refusal the queue can decide at once (a red required check, a head that moved since you fetched it, a behind branch with no workflow that declares on: merge_group) fails the command with the reason. A pull request that is merely waiting prints its queue position.

Use --auto when you want the intent to outlive the command, for example right after opening a pull request whose checks have not run yet. Plain neo pr merge sends the head it just fetched, so a concurrent push turns the merge into an error; --auto sends no such guard, because a head read a moment too early would otherwise get the armed merge ejected as “source branch moved”.

On the web, Merge joins the queue straight away. While the merge gate is still blocked, Enable auto-merge arms the pull request instead: it waits for the requirements, then merges with the repository’s default method.

While queued, the merge box shows Leave queue, and View merge queue opens the target branch’s queue. An armed merge shows “Auto-merge armed by …” with Disable auto-merge; anyone with write access can disarm it, and the merge is attributed to whoever armed it.

  • A failing check on the queue’s candidate removes the pull request from the queue and leaves it open. The merge box shows Removed from merge queue with the reasons, and Retry merge.
  • Pushing new commits removes it from the queue and disarms auto-merge. Merge again once you have seen the new head.
  • Whoever armed the merge, or asked for it, is notified when the queue removes it.

The merge box shows who merged it. If other pull requests were stacked on it, they are retargeted onto its base. In the commit list, the landed commit links back to the pull request, and when its files are identical to the pull request’s last commit, that commit’s CI results are shown for it.

Press Close in the merge box, or:

Terminal window
neo pr close 42 --comment "Superseded by #57."

Closing a queued pull request takes it out of the queue. A closed pull request cannot be reopened. To continue the work, open a new one; if the branch tip is still the commit the closed pull request was opened at, the new one is refused as a duplicate, so push a commit first.

Task Command
List open (or --state all) pull requests neo pr list
Diffstat, checks, reviews and comments neo pr view 42
One JSON pack for a script or an agent neo pr context 42
Change the title or description neo pr edit 42 --title …
Mark ready, or back to draft neo pr ready 42 / neo pr ready 42 --undo
Wait for CI, or for the merge neo pr wait 42 / neo pr wait 42 --for merged
Merge or queue, or arm it neo pr merge 42 / neo pr merge 42 --auto