GitHub Actions Merge Queues: Run Required Checks on the Exact Combined Commit
Configure GitHub Actions for merge queues so required checks validate queued commits, report reliably, and keep merge throughput predictable.
A pull request can pass CI on its own and still break the target branch when it is combined with another change. A merge queue addresses that integration gap by testing a temporary merge group against the latest base branch and any changes ahead of it in the queue. That benefit depends on CI actually running for the merge-group event and reporting every required check against the commit the queue asked it to test.
This is not equivalent to testing the pull request head, adding a push trigger, or running a workflow manually. GitHub Actions treats merge_group as a separate event from pull_request and push. If branch protection requires a check that never runs for the merge group, the queue waits for the missing result and cannot complete the merge.
Add merge_group as a real CI trigger
For a GitHub Actions workflow that supplies required pull request checks, include merge_group as an additional trigger. Keep the event separate from pull_request so it is clear that both the developer’s proposed change and the combined queue commit receive CI:
name: Required CI
on:
pull_request:
branches: [main]
merge_group:
types: [checks_requested]
permissions:
contents: read
jobs:
required-ci:
name: required-ci / build-and-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
- run: npm ci
- run: npm test
- run: npm run build
The sample assumes a Node project with a committed .nvmrc and corresponding npm scripts. Substitute the repository’s actual test and build commands. The checkout action uses the event’s commit by default; do not override ref to a pull request head SHA in the merge_group path, or the test could silently inspect the individual change instead of the combined candidate.
The trigger should run the same required validation on both event types, but the test matrix may differ when there is a measured reason. If the queue event omits a required job, uses a different condition, or checks out another commit, a successful pull request run does not compensate. Inspect an actual merge_group run and verify its checked-out SHA matches the queued commit shown in GitHub.
The workflow-level branches filter in the example applies only to pull_request. Do not copy an unreviewed pull-request branch filter onto merge_group. A merge-group ref is a temporary queue ref, and a filter that does not match can suppress the check the queue is waiting for. GitHub’s merge-queue guidance also warns that skipping required workflows can leave required checks pending. Keep the reporting workflow active for queue candidates, and put any narrower optimization inside jobs only after confirming that the required check still reports a conclusive result.
Understand what the queue is testing
When a pull request enters the queue, GitHub constructs a merge group from the current base branch and queued changes that precede or accompany that pull request. The resulting synthetic commit has its own SHA. GitHub asks CI to evaluate that group; it is not enough for the pull request’s original head SHA to have been green earlier.
This distinction catches integration failures such as two individually valid changes that both edit the same generated file, rely on conflicting configuration, or make incompatible assumptions about an API. The check result applies to the tested combined snapshot. When a required check fails, the queue can remove the failing pull request and rebuild later candidates without it. A queue position is therefore conditional on the base and preceding changes that were included in that candidate.
For a third-party CI provider, configure it to react to the queue’s temporary branch prefix, gh-readonly-queue/{base_branch}, and report status for the merge-group SHA. Do not assume a CI integration that listens only for ordinary pull request refs will notice those temporary queue refs. Confirm the provider’s event and status API behavior with a test repository or protected staging branch before requiring the queue on a critical branch.
Make required check names and outcomes dependable
A merge queue waits for required checks configured on the target branch’s protection rule or ruleset. Use stable, distinguishable job names for checks that branch protection requires. If separate workflows emit ambiguous duplicate check names, reviewers may not be able to tell which one branch protection is enforcing. Before enabling the queue, inspect the required status checks in branch settings and compare them with the check runs emitted by both a pull_request event and a merge_group event.
Avoid workflow-level path filters on the only workflow that reports a required check. A skipped workflow cannot report its required result, so the queue may remain waiting even when the change appears unrelated. If the repository needs path-based savings, keep a small always-triggered gate that determines which validation suites are relevant and still reports a stable conclusion. Test changes to workflow files, lockfiles, shared libraries, generators, and configuration separately: these often affect more code than their path suggests.
A job that is skipped by an internal condition and a workflow that never starts are not the same operational outcome. Verify the required-check behavior in the repository’s actual ruleset rather than treating a green check on the pull request as proof that merge_group coverage exists. Test both successful and failing merge groups, and confirm that a missing check becomes visible as a wait or failure rather than being silently interpreted as validation.
Keep release side effects out of queue validation
A merge-group workflow is a pre-merge validation of a temporary candidate, not a production deployment event. Keep publication, release tagging, and production deployment on the appropriate post-merge or explicitly approved release path. A queue may rebuild a group as earlier pull requests arrive, fail, or leave; deployment side effects in this validation path can run against commits that never become the target branch.
Separate read-only validation from jobs that publish packages or deploy infrastructure. If a workflow handles multiple events, use explicit job conditions and minimal token permissions so a merge_group run cannot inherit a release action merely because the same file also handles a release trigger. Confirm that the release workflow consumes the merged branch commit or reviewed immutable artifact, not a temporary merge-group ref.
The queue checks compatibility with the candidate integration snapshot. They do not replace review, branch protection, artifact provenance, or post-deployment health checks. A passing merge group says that the configured checks passed for the combined commit under the tested environment; it does not guarantee production runtime health or prove that a later deployment used that exact commit.
Tune throughput without weakening validation
GitHub exposes separate controls for how many merge_group webhooks may be dispatched concurrently and how many pull requests may be merged together. Build concurrency is a CI throughput limit; merge limits define queue batching behavior after required checks pass. Increasing either can raise resource use and change queue latency, but one setting does not substitute for the other.
Start with a build concurrency value the CI fleet can sustain without starving ordinary pull request jobs. Measure queue wait time, workflow duration, runner saturation, retries, and failure rate before adjusting it. Large matrices and long-running integration suites can turn merge-group validation into the queue’s bottleneck. Cache deterministic dependencies, fan out independent tests, and preserve a smaller required gate for fast, high-signal checks, but do not remove a correctness check simply to improve the queue’s apparent speed.
A merge group can include multiple pull requests, so the same expensive workflow may run more than once as the queue advances or is rebuilt. Keep tests deterministic and avoid external state mutations that make a retry produce different results. Use unique test namespaces and clean them up. Never let concurrently evaluated merge groups write to one shared environment unless that environment provides isolation and serialization.
When choosing merge limits, account for deployment and operational boundaries. A group that satisfies checks can merge multiple pull requests together. If every merge to the base branch automatically starts a deployment, a large batch can also mean a larger deployment change set. Set batch size and timeout based on review practices, test duration, and the cost of diagnosing a combined failure, not merely on maximum theoretical throughput.
Enable the queue in a controlled sequence
First update CI and validate it while the queue is not yet required. Create a low-risk pull request, add it to a test queue, and confirm that GitHub emits merge_group with checks_requested, the workflow starts, and the jobs test the queue commit. Then test a deliberately failing change and verify that the queue reports the failure and removes or re-forms the affected candidate as expected.
Next, compare the actual check names with the checks selected in branch protection or the ruleset. Enable the queue on a protected branch only after every required check is present for merge_group events. GitHub documents that merge queues are not available for every repository plan; confirm plan and repository ownership eligibility before designing a rollout around them. Its current guidance also says a merge queue cannot be enabled with branch protection rules whose branch-name pattern uses wildcard characters.
Monitor queue state and failed entries after activation. A pull request may leave the queue because checks failed, the CI response timed out, a conflict could not be reconciled, or a user removed it. Diagnose the event, SHA, check run, and base state together rather than rerunning an unrelated pull_request job and assuming the queued candidate is now validated.
Production verification checklist
- Required CI listens to both pull_request and merge_group, with checks_requested configured for the queue event.
- Queue runs check out and test the exact merge-group commit, not a manually substituted pull request head.
- Every required check reports under the expected, stable name for both event paths.
- No workflow-level path or branch filter suppresses required queue checks.
- Release, package publication, and deployment side effects do not run for temporary merge-group candidates.
- Test environments are isolated and safe under concurrent merge-group runs.
- Build concurrency and PR merge limits are tuned independently using observed queue and runner metrics.
- A staging queue has exercised success, failure, regrouping, and missing-check behavior before production enforcement.
- Repository plan eligibility and branch-protection pattern constraints are checked before activation.
- Queue failures are diagnosed from the specific event SHA and check result, not from an unrelated PR run.
A merge queue is only as reliable as the checks it can observe. Trigger the right event, validate the exact combined commit, report stable results, and keep deployment effects outside the temporary candidate path. With those boundaries in place, the queue can protect a busy branch without forcing every author to repeatedly rebase and wait for the same checks.
Related:
- GitHub Actions Concurrency Groups: Cancellation, Queues, and Safe Deployment Serialization
- GitHub Actions Reusable Workflows: Contracts, Permissions, and Safe Composition
Sources: