Skip to content

How the queue works

Gondolier is a batch merge queue. Instead of testing and merging pull requests one at a time, it groups the ready ones, tests them together, and lands the set that passes.

The engine underneath is shunt, and its whole model is three words: stage → gate → bisect.

When pull requests are ready to merge, Gondolier creates a staging branchgondolier/<base>-<timestamp>-<n> — containing your base branch plus every PR in the batch, merged together.

Nothing has touched your base branch at this point. The staging branch is a throwaway; it exists so your CI has something to test.

Your CI runs on that staging branch, because it matches gondolier/**. Gondolier does not run your tests — it watches for the result.

This is why a repository needs CI that triggers on gondolier/** pushes. If nothing runs, nothing reports, and the batch waits. The CI gate setup walks through it.

If the batch passes, every PR in it merges and the staging branch is deleted.

If it fails, Gondolier does not reject the whole batch. It splits it and tries again — …-1 becomes …-1-1 and …-1-2 — narrowing down until it finds the pull request that actually broke. That PR is bounced; everything else in the batch lands.

This is the point of batching. Ten compatible PRs cost roughly one CI run instead of ten, and a single bad one does not block the other nine.

A bounced PR is one the queue identified as the cause of a failure. It is taken out of the queue and left open for you to fix. Nothing is closed, nothing is force-pushed, and no work is lost.

Push a fix and it re-enters the queue like any other ready PR.

Gondolier reconciles on a five-minute cron tick. Neither wake mode dispatches work directly: a webhook marks a repository due, and the tick is what runs it. So the worst case in webhook mode is one tick — about five minutes — and a quiet poll repository can wait up to an hour, because it backs off while idle. The numbers are tabulated in the setup guide.

This bounds throughput by design. A merge queue that reacted instantly to every event would be testing one pull request at a time — the batching is the product, and waiting for the tick is what collects a batch worth testing.

  • Creates and deletes gondolier/** staging branches.
  • Posts a status check (default context gondolier) on pull requests.
  • Merges pull requests that pass, using your configured merge style.
  • Registers a webhook, in webhook wake mode.
  • Adds a required status check to your base branch — only when you ask it to. See Branch protection.
  • Force-push anything.
  • Close or modify your pull requests’ contents.
  • Touch branches outside gondolier/**, other than merging into your base.
  • Merge a pull request whose gate did not pass.
  • Remove branch protection you configured yourself.
Term Meaning
Batch The set of pull requests staged and tested together
Staging branch gondolier/<base>-<timestamp>-<n> — the throwaway branch CI tests
Gate Your CI result on a staging branch
Bisect Splitting a failed batch to find the PR responsible
Bounce Removing that PR from the queue, leaving it open
Tick The five-minute reconciliation cycle
Connection A forge instance plus the bot account Gondolier acts as
Managed repository A repository enrolled in the queue