Mergify Merge Queue

作者 mergifyioe7c1ebbc2813無授權條款收錄於 2026年10月8日更新於 2026年10月8日

Use Mergify merge queue to queue/dequeue PRs, to monitor and inspect the queue, and to diagnose a dequeued PR — whether it is queued, why it was dequeued, where its CI failure is, and what to do next. ALWAYS use this skill when queuing or dequeuing a PR, checking queue status, investigating PR merge state, finding out why a PR left the queue, pausing/unpausing the queue, or debugging merge failures. Triggers on queue a PR, requeue, dequeue, dequeued, why was my PR dequeued, dequeue reason, merge queue, queue status, queue pause, queue show, pause, unpause, frozen, bisecting, batch, CI checks, CHECKS_FAILED, PULL_REQUEST_UPDATED.

僅含說明DevOps & Cloud
AI 產生的概覽

操作並診斷 Mergify 合併佇列:將 PR 排入或移出佇列、查看佇列狀態並解釋移出原因。

功能
本技能說明如何使用 Mergify 合併佇列:透過 PR 留言將提取要求排入、移出與重新排入佇列,並使用 Mergify CLI 監控佇列狀態。它說明如何判斷 PR 是已排入佇列、已移出佇列、由佇列合併,還是從未排入佇列,並介紹如何透過 queue show 指令、Mergify 活動記錄 API、Mergify Merge Queue 檢查執行與 Merge Queue Status 留言來診斷移出佇列。內容也涵蓋佇列狀態查看、佇列狀態意義、暫停與恢復,以及移出佇列代碼與後續操作對照表。
適用情境
適用於將提取要求排入、移出或重新排入佇列,查看合併佇列狀態,或排查 PR 為何離開佇列或未能合併的情況。也用於暫停或恢復佇列,以及偵錯合併佇列的 CI 失敗。
執行需求
需要 Mergify CLI 和 Mergify 權杖(直接呼叫 API 時使用 MERGIFY_TOKEN);GitHub 端介面需要 GitHub CLI 存取權。需要連線至 Mergify API 與 GitHub 的網路。本技能不附帶指令碼,僅為說明文件。

Mergify Merge Queue

Overview

The merge queue serializes PR merges, running CI on temporary merge commits to catch integration failures before they reach the target branch. Use comments on the PR to queue/dequeue it, and the CLI to monitor queue state, inspect individual PRs, and manage the queue.

mergify queue show <PR> reports on a PR that is no longer in the queue too — whether it was dequeued, merged by the queue, or never queued, and why — so start there for a PR that vanished from the queue. See Diagnosing a dequeued PR; the GitHub-side surfaces documented there are the fallback for when the CLI cannot read the activity log.

Queuing and Dequeuing a PR

Queue, dequeue, and requeue actions are driven by comments on the pull request, not the CLI:

CommentEffect
@mergifyio queueAdd the PR to the merge queue (also use to requeue a PR that was dequeued)
@mergifyio dequeueRemove (dequeue) the PR from the merge queue

@mergifyio requeue is accepted, but it is a deprecated alias that runs the same command as @mergifyio queue — there is no separate requeue behavior. Post @mergifyio queue.

When Mergify processes the comment, it adds a 👍 (thumbs up) reaction to the comment to acknowledge receipt. After queuing, use mergify queue show <PR_NUMBER> to watch the PR's status as it progresses through the queue.

Commands

bash
mergify queue status                 # Show queue status (batches, waiting PRs)mergify queue status --branch main   # Filter by branchmergify queue status --json          # Machine-readable JSON outputmergify queue show <PR_NUMBER>       # Detailed state of a PR in the queuemergify queue show <PR_NUMBER> -v    # Full checks table and conditions treemergify queue show <PR_NUMBER> --json # Machine-readable JSON outputmergify queue pause --reason "..."   # Pause the queue (requires reason)mergify queue unpause                # Resume the queue

That is the whole queue group: status, show, pause, unpause. There is no subcommand for dequeuing a PR — the dequeue reason comes from queue show on a PR that has left the queue, not from a flag. For the full queue trail (every enter / checks / leave event, not just the last exit), use mergify events --pr <PR> --since 90d — see the mergify-events skill.

Is the PR queued, dequeued, or never queued?

Start here — the rest of the workflow branches on this answer.

mergify queue show <PR> answers all four cases. A PR with no queue entry is a normal answer, not an error: the command prints a notice and exits 0 in every case below.

queue show resultMeaning
PR #N block with position / CI stateThe PR is in the queue
PR #N was dequeued <when> + a Dequeue codeIt left the queue without merging — see the reason table
PR #N was merged by the merge queue <when>It left the queue by merging. Not a dequeue
PR #N is not in the merge queueNo queue activity in the retained window — never queued, aged out, or not a real PR number

Under --json, a PR that is not currently queued carries queued: false plus a dequeued discriminator:

bash
mergify queue show 1234 --json | jq -e '.queued == false' >/dev/null && echo "not in queue"
  • dequeued: true — left without merging; the raw leave event is under queue_leave
  • dequeued: false — merged by the queue, or never queued (queue_leave tells the two apart: null means never queued)
  • dequeued: null — the lookup itself failed, and queue_leave_error says why. Not the same as "never queued" — fall back to the GitHub-side surfaces rather than concluding anything

queue_leave_head_sha carries the head the diagnosis describes. Compare it against the PR's current head before reporting anything from it — a dequeue is often caused by a push, so its failing checks routinely belong to a commit the PR no longer has:

bash
mergify queue show 1234 --json | jq -r '.queue_leave_head_sha'   # 31b4a485b8ce…gh pr view 1234 --json headRefOid -q .headRefOid                 # 340361aae580…  → superseded, stay quiet

Two limits to keep in mind. History goes back 90 days (the activity log's retention), so an older dequeue reads as "no activity". And the command does not check that the PR exists, so a typo'd number prints the same "not in the merge queue" notice — confirm the PR is real (gh pr view <PR>) before concluding it was never queued.

Do not use the presence of a Mergify Merge Queue check run as the test — a PR that merely matches the queue conditions gets one titled Waiting for queue conditions without ever being queued. A # Merge Queue Status comment is a reliable positive signal (the pre-queue "Queue this pull request" offer comment deliberately carries no such heading), but its absence proves nothing, since the comment can be disabled per repository.

Diagnosing a dequeued PR

Four surfaces carry the reason. Prefer them in this order.

1. mergify queue show <PR> (start here)

On a PR that is no longer queued, queue show reads the PR's last merge-queue exit and renders it:

PR #37823 was dequeued 24m ago
  Dequeue code:  CHECKS_FAILED  Queue:         default  Queued at:     46m ago  Trigger:       merge queue internal  Head SHA:      31b4a48
  The merge conditions cannot be satisfied due to failing checks
  - `@github-actions/all-greens`
  Failing checks:    ✗ all-greens  failure      https://github.com/Mergifyio/monorepo/actions/runs/…/job/…
  Fix the cause above, then comment `@mergifyio queue` on the pull request.

That is the engine's own explanation plus the failing checks with their job-log URLs — go straight to the failing job rather than hunting for it. The explanation is capped at 12 lines in compact mode; add -v for the whole thing (a PR_DEQUEUED reason embeds the full unmet-condition tree, which runs to dozens of lines).

Head SHA is the commit all of that describes. If it is not the PR's current head, the report is about a commit that has since been replaced — the checks above may already be green again. Check it before acting on the failure.

--json gives the same thing machine-readably: dequeued, plus queue_leave carrying the raw event, so read dequeue_code, reason, and unsuccessful_checks[].details_url from .queue_leave.metadata. Use the promoted queue_leave_head_sha for the staleness check above.

Reading the activity log is best-effort: a token scoped to the merge queue can be refused the repository's event log (403). The command then degrades to the plain "not in the merge queue" notice plus a warning on stderr, and reports dequeued: null — that is the signal to fall through to the surfaces below, not a statement that the PR was never queued.

2. The Mergify activity log (what surface 1 reads underneath)

GET /v1/repos/{owner}/{repo}/logs returns the queue lifecycle events, newest first. queue show calls this for you, and mergify events --pr <PR> --since 90d (the mergify-events skill) browses the whole lifecycle from the CLI — including every event type, not just queue ones. Go direct with curl only when it degrades (403 above, with a token that can read the log) or from somewhere the CLI is not installed:

MERGIFY_TOKEN must hold a Mergify token: a GitHub token still works against the Mergify API but is deprecated, and the credential mergify auth login stores lives in the OS keychain rather than the environment, so a raw curl cannot reach it.

bash
REPO=owner/repoPR=1234FROM=$(date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-90d +%Y-%m-%dT%H:%M:%SZ)
curl -sS -H "Authorization: Bearer ${MERGIFY_TOKEN:?set a Mergify token}" \  "https://api.mergify.com/v1/repos/$REPO/logs?pull_request=$PR&event_type=action.queue.leave&received_from=$FROM" \| jq 'if .events == [] then "no leave event in window — never queued (or aged out)"      else .events[0].metadata           | {merged, dequeue_code, reason,              failing: [.unsuccessful_checks[]? | {name, state, details_url}]}      end'
json
{  "merged": false,  "dequeue_code": "CHECKS_FAILED",  "reason": "The merge conditions cannot be satisfied due to failing checks\n\n- `ci-gate`",  "failing": [    {      "name": "ci-gate",      "state": "failure",      "details_url": "https://github.com/owner/repo/actions/runs/28589756829/job/84771312071"    }  ]}

Read it as:

  • "events": [] / size: 0 → no leave event in the window → the PR was never queued (or the event aged out; see the window rule below).
  • merged: true → it left the queue by merging. Not a dequeue.
  • merged: false → it was dequeued; dequeue_code says why (see the reason table).
  • unsuccessful_checks[].details_url → direct link to the failing CI job log. This is how you reach the CI failure after the PR has left the queue.

Two traps that make this silently return nothing:

  • received_from is required in practice. The window defaults to the last 24 hours. A dequeue from last week returns size: 0 with no error, which reads exactly like "never queued". Always pass received_from.
  • The window may not exceed 93 days (retention is 90 days) or the call fails with 422 'received_from' and 'received_to' cannot span more than 93 days.

Same endpoint, other useful filters: &outcome=failure restricts leave events to dequeues (a merge is success); drop event_type to see the whole lifecycle (action.queue.enter, checks_start, checks_end, leave).

3. The Mergify Merge Queue check run

The check-run title names the reason directly, and its summary is the full queue report:

bash
SHA=$(gh pr view $PR --repo $REPO --json headRefOid -q .headRefOid)gh api "repos/$REPO/commits/$SHA/check-runs" \  -q '.check_runs[] | select(.name=="Mergify Merge Queue") | {conclusion, title: .output.title, summary: .output.summary}'

Titles map to state without any parsing:

output.titleState
Dequeued — <reason> (conclusion neutral)Dequeued, reason in the title
Dequeued from merge queue (conclusion neutral)Dequeued, but the reason did not resolve to a named code — use surface 1
Merged via merge queue (conclusion success)Merged by the queue
Waiting for queue conditions, Checks …, In merge queueStill in the lifecycle

Caveat: the check run lives on the head SHA it was written against. If the dequeue was caused by a push (PULL_REQUEST_UPDATED, DRAFT_PULL_REQUEST_CHANGED), the current head has a fresh check run and the dequeue report sits on the previous SHA. Use surface 1 or 4 in that case — surface 1 names the SHA (Head SHA / queue_leave_head_sha), so it is the one that lets you detect the mismatch rather than fall into it. Note also that gh pr view --json statusCheckRollup returns a null title — go through gh api .../check-runs as above.

4. The # Merge Queue Status comment

mergify[bot] posts one comment per queue session, so read the last one. It survives pushes, which makes it the most robust GitHub-side surface.

bash
gh api --paginate --slurp "repos/$REPO/issues/$PR/comments" \| jq -r '[.[][] | select(.user.login=="mergify[bot]")              | select(.body|contains("# Merge Queue Status"))] | last | .body'

--paginate matters: the endpoint returns 30 comments per page and the newest are on the last page, so without it last silently hands you a stale status comment (or none) on any PR with real discussion. --slurp collects the pages into an array of arrays — hence .[][] to flatten — and is incompatible with -q, so the filter goes through jq instead.

Its structure, in order: a hidden JSON payload, a timeline, the merge conditions, then ## Reason, Failing checks: (each with a [job log] link), and ## Hint. The hidden payload gives the state without parsing prose:

<!--- ... {"version": 1, "state": "dequeued", "queue_rule_name": "default", ...} ... -->

state is one of waiting, checking, frozen, bisecting, merged, dequeued. It does not carry the dequeue code — that is in the ## Reason prose below it.

Caveat: this comment can be turned off per repository (merge_queue.status_comments: none, or outcomes for terminal events only). Absence of a comment does not prove the PR was never queued.

Dequeue reasons and what to do next

dequeue_code values and the action they call for. The engine ships a per-reason ## Hint in the report — for a code not listed here, read that Hint rather than guessing.

dequeue_codeWhat happenedWhat to do next
PR_MERGEDMerged by the queueNothing — this is success
PR_MANUALLY_MERGEDMerged outside the queueNothing
CHECKS_FAILEDRequired checks failed on the merge commitRead unsuccessful_checks[].details_url, fix the CI. Pushing a fix requeues it automatically once conditions match again; if it was flaky, requeue as-is with @mergifyio queue
CHECKS_TIMEOUTchecks_timeout elapsed before conditions were satisfiedCheck the reason's details: checks that never reported mean the check names in your conditions don't match what CI publishes (fix the config, not the PR). Checks still running mean CI is too slow or stuck
PULL_REQUEST_UPDATEDSomeone pushed to the PR while it was queuedStop pushing to a queued PR. Requeue when the branch is final
DRAFT_PULL_REQUEST_CHANGEDThe queue's draft/batch PR got commits Mergify did not createNever push to the merge-queue draft branch. Requeue the original PR
CONFLICT_WITH_BASE_BRANCHThe PR conflicts with its base branchRebase or merge the base branch, resolve conflicts, then requeue
CONFLICT_WITH_PULL_AHEADThe PR conflicts with a PR ahead of it in the queueWait for the PR ahead to merge, then rebase and requeue
BRANCH_UPDATE_FAILEDMergify could not update the PR's head branchRead the reason details, update the branch yourself, requeue
BASE_BRANCH_MISSING / BASE_BRANCH_CHANGEDThe base branch is gone or changedRetarget the PR to a live base branch, then requeue
PR_MANUALLY_DEQUEUEDA human removed it (command, dashboard, or API)The reason names who and how. Requeue only once you know why they pulled it
PR_DEQUEUEDQueue conditions stopped matchingLook at the conditions in the report; fix the PR or requeue
DROPPED_BY_BISECTION_ELIMINATIONBisection blamed other PRs and dropped this one untestedIt is unproven, not known-broken. Requeue to test it on its own
STACK_PREDECESSOR_DEQUEUEDA predecessor in the same stack was dequeuedFix the predecessor, requeue the stack
QUEUE_RULE_MISSING / CONFIGURATION_CHANGEDThe config changed under the queued PRFix .mergify.yml (see the mergify-config skill), then requeue
INCOMPATIBILITY_WITH_BRANCH_PROTECTIONSQueue settings clash with branch protectionsReconcile the repository's branch protections with the queue config — requeuing alone will not help
UNPROCESSABLE_PULL_REQUESTToo many check runs, comments, or files for Mergify to processShrink the PR

Not every code means the PR left the queue. These reasons interrupt the checks and the PR stays queued — do not treat them as a dequeue and do not requeue:

PR_AHEAD_DEQUEUED, BATCH_AHEAD_FAILED, PR_WITH_HIGHER_PRIORITY_QUEUED, MERGE_QUEUE_RESET, SCHEDULED_FREEZE_STATUS_CHANGED, SPECULATIVE_CHECK_NUMBER_REDUCED, INTERMEDIATE_RESULTS_SKIPPED, CHECKS_RETRIED, BATCH_SCOPES_CHANGED, SCHEDULE_BLOCKED_AHEAD_YIELDED, PR_CHECKS_STOPPED_BECAUSE_MERGE_QUEUE_PAUSE

They arrive as abort_code on an action.queue.checks_end event (with aborted: true) rather than as dequeue_code on a leave event, and the check-run title reads Checks restarted — … or Checks aborted — … rather than Dequeued — …. The authoritative test for "did it actually leave the queue" is an action.queue.leave event with merged: false — not the presence of a code from this list.

Checking Queue Status

Use mergify queue status to see the current state of the merge queue:

  • Batches: groups of PRs being tested together, shown with their CI status and ETA
  • Waiting PRs: PRs queued but not yet in a batch, shown with priority and queue time
  • Pause state: whether the queue is paused and why

Use --json when you need to parse the output programmatically.

Inspecting a PR in the queue

Use mergify queue show <PR_NUMBER> to check why a PR is stuck or how it's progressing:

  • Position: where the PR sits in the queue
  • Priority: which priority rule matched
  • CI timeout: when the queue will give up on the PR's checks (- when no timeout is configured) — watch this to catch a CHECKS_TIMEOUT before it fires
  • CI state: whether checks are passing, pending, or failing
  • Conditions: which conditions are met and which are blocking
  • Use -v (verbose) for the full checks table and conditions tree

-v lists check names and states only — no links to the CI jobs. For job-log URLs on a PR that is still queued, use the GitHub-side surfaces above (the check-run summary and the status comment); once the PR has left the queue, queue show itself prints them. --json is a raw passthrough of the API payload, so it carries one more field the human render drops: queue_rule (the resolved queue rule config, not just its name).

Queue States

StateMeaning
runningBatch is actively running CI
preparingBatch is being set up
bisectingBatch failed, bisecting to find the culprit
failedCI failed for this batch
mergedPRs in this batch have been merged
waiting_for_mergeCI passed, waiting for GitHub to merge
waiting_for_previous_batchesBlocked on earlier batches completing
waiting_for_batchWaiting to be picked up into a batch
waiting_for_requeueA batch ahead failed; this batch will be re-embarked
waiting_scheduleOutside the configured merge schedule
frozenQueue is paused

Pausing and Unpausing

Pause the queue to temporarily halt all merges (e.g., during incidents or deployments):

bash
mergify queue pause --reason "production incident — halting merges"mergify queue unpause
  • Pausing does not cancel running CI — it prevents new merges from starting
  • The reason is visible to all team members in the queue status
  • Use --yes-i-am-sure to skip the confirmation prompt in scripts

Troubleshooting

PR not entering the queue:

  • Make sure the PR was queued: post @mergifyio queue and confirm Mergify reacted with 👍 on the comment
  • Check that the PR's merge conditions are met: mergify queue show <PR_NUMBER> -v
  • Look at the conditions section for unmet requirements
  • Do not assume the queue command never landed: queue show tells a PR that was queued and dequeued apart from one that never entered

PR stuck in queue:

  • Check CI state: mergify queue show <PR_NUMBER>
  • If checks are failing, -v names them; for the job logs, read the Failing checks: links in the # Merge Queue Status comment or the Mergify Merge Queue check-run summary
  • If the queue is paused, check who paused it: mergify queue status

PR disappeared from the queue:

  • mergify queue show <PR_NUMBER> — it says whether the PR was dequeued, merged by the queue, or never queued, and prints the dequeue code, the reason, and the failing checks' URLs
  • Never assume "not in the merge queue" means "never queued": read the headline (or dequeued under --json) before telling anyone to requeue
  • Then act per the reason table

Queue moving slowly:

  • Check for failing batches that trigger bisection: mergify queue status
  • Bisecting batches test PRs individually, which is slower than batch merging

來源與署名

來源:mergifyio/mergify-cli位於skills/mergify-merge-queue提交e7c1ebb

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架