关于 mergify-merge-queue
通过 PR 评论和 `mergify` 命令行操作 Mergify 合并队列的 Skill。它说明如何监控和诊断队列,包括区分已移出、已合并和从未入队的 PR,并查看失败原因。
主要功能
- 01队列状态与 PR 详情命令
- 02暂停和恢复队列
- 03诊断队列退出状态
- 04CI 失败详情与任务日志链接
- 05用于检查队列的 JSON 输出
适用场景
- 01监控 PR 排位与 CI 进度
- 02查明 PR 离开队列的原因
- 03确认 PR 是已合并还是已移出队列
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mergifyio/ mergify-cli --skill mergify-merge-queue安装后在 Claude Code 中输入/mergify-merge-queue确认已加载。
详细介绍
Mergify 合并队列
概述
合并队列会按顺序合并 PR,并在临时合并提交上运行 CI,以便在更改进入目标分支前发现集成失败。通过在 PR 上发表评论来将其加入或移出队列,并使用 CLI 监控队列状态、检查单个 PR 和管理队列。
mergify queue show <PR> 也会报告已不在队列中的 PR——无论它是被移出队列、由队列合并,还是从未入队,以及原因——因此,如果某个 PR 从队列中消失,请先从这里开始查看。请参阅诊断已移出队列的 PR;当 CLI 无法读取活动日志时,该文档介绍的 GitHub 端界面是备用方案。
将 PR 加入队列和移出队列
加入队列、移出队列和重新入队操作由拉取请求上的评论触发,而非 CLI:
| 评论 | 效果 |
|---|---|
@mergifyio queue | 将 PR 加入合并队列(也用于将已移出队列的 PR 重新入队) |
@mergifyio dequeue | 从合并队列中移除(移出队列)PR |
@mergifyio requeue 也受支持,但它是已弃用的别名,执行的命令与 @mergifyio queue 相同——并没有单独的重新入队行为。请发布 @mergifyio queue。
Mergify 处理评论后,会在评论上添加 👍(竖起大拇指)回应,以确认已收到。将 PR 加入队列后,使用 mergify queue show <PR_NUMBER> 查看 PR 在队列中的进度状态。
命令
mergify queue status # Show queue status (batches, waiting PRs)
mergify queue status --branch main # Filter by branch
mergify queue status --json # Machine-readable JSON output
mergify queue show <PR_NUMBER> # Detailed state of a PR in the queue
mergify queue show <PR_NUMBER> -v # Full checks table and conditions tree
mergify queue show <PR_NUMBER> --json # Machine-readable JSON output
mergify queue pause --reason "..." # Pause the queue (requires reason)
mergify queue unpause # Resume the queue
queue 命令组仅包含这些命令:status、show、pause、unpause。没有用于将 PR 移出队列的子命令——对于已离开队列的 PR,其移出原因请通过 queue show 查看,而非使用某个标志。要查看完整的队列轨迹(每一次进入 / 检查 / 离开事件,而不仅是最后一次退出),请使用 mergify events --pr <PR> --since 90d——参阅 mergify-events 技能。
PR 已排队、已出队,还是从未排队?
从这里开始——后续工作流会根据这个答案分支。
mergify queue show <PR> 可回答这四种情况。没有队列条目的 PR 是正常结果,不是错误:在以下所有情况下,命令都会显示提示并以 退出码 0 退出。
queue show 结果 | 含义 |
|---|---|
PR #N 区块,包含位置 / CI 状态 | PR 在队列中 |
PR #N was dequeued <when> + Dequeue code | PR 未合并便离开了队列——参见原因表 |
PR #N was merged by the merge queue <when> | PR 通过合并离开了队列。不是出队 |
PR #N is not in the merge queue | 保留时间窗口内没有队列活动——从未排队、记录已过期,或这不是一个有效的 PR 编号 |
在 --json 下,当前未排队的 PR 会包含 queued: false 以及一个 dequeued 判别字段:
mergify queue show 1234 --json | jq -e '.queued == false' >/dev/null && echo "not in queue"
dequeued: true— 未合并便离开队列;原始离队事件位于queue_leavedequeued: false— 由队列合并,或从未排队(queue_leave可区分两者:null表示从未排队)dequeued: null— 查询本身失败,queue_leave_error会说明原因。这不等于“从未排队”——请改查 GitHub 端的信息来源,不要据此下结论
queue_leave_head_sha 表示诊断所针对的提交。在依据它报告任何信息之前,请将其与 PR 当前的 head 进行比较——出队往往是由推送触发的,因此检查失败通常属于 PR 已不再包含的提交:
mergify queue show 1234 --json | jq -r '.queue_leave_head_sha' # 31b4a485b8ce…
gh pr view 1234 --json headRefOid -q .headRefOid # 340361aae580… → superseded, stay quiet
请牢记两个限制。历史记录仅保留 90 天(活动日志的保留期限),因此更早的出队会显示为“没有活动”。此外,该命令不会检查 PR 是否存在,所以输错编号也会显示相同的“not in the merge queue”提示——在断定 PR 从未排队之前,请确认 PR 确实存在(gh pr view <PR>)。
不要将是否存在 Mergify Merge Queue 检查运行记录作为判断依据——仅仅符合队列条件的 PR 也会出现一条标题为 Waiting for queue conditions 的记录,但它从未真正入队。# Merge Queue Status 评论是可靠的肯定信号(入队前的“Queue this pull request”邀请评论有意不包含此标题),但没有该评论不能证明什么,因为仓库可以禁用此评论。
诊断已出队的 PR
有四个信息来源会提供原因。请按以下顺序优先查看。
1. mergify queue show <PR>(从这里开始)
对于已不在队列中的 PR,queue show 会读取该 PR 最近一次离开合并队列的记录并将其呈现出来:
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.
这是引擎自身给出的解释,以及包含作业日志 URL 的失败检查——可直接查看失败的作业,无需四处查找。紧凑模式下,解释最多显示 12 行;添加 -v 可查看完整内容(PR_DEQUEUED 原因会嵌入完整的未满足条件树,可能长达数十行)。
Head SHA 是以上所有信息所针对的提交。如果它不是 PR 当前的 head,说明报告针对的是已被替换的提交——上述检查可能已经再次通过。请先核对,再根据失败信息采取行动。
--json 会以机器可读的形式提供相同信息:dequeued,以及包含原始事件的 queue_leave。请从 .queue_leave.metadata 中读取 dequeue_code、reason 和 unsuccessful_checks[].details_url。使用提升后的 queue_leave_head_sha 进行上述过期检查。
读取活动日志属于尽力而为:仅具有合并队列权限范围的令牌可能无法读取仓库的事件日志(403)。此时,命令会退化为显示普通的“not in the merge queue”提示,并在 stderr 上输出警告,同时报告 dequeued: null——这就是应转而查看下方信息来源的信号,并不代表 PR 从未排队。
2. Mergify 活动日志(底层由界面 1 读取)
GET /v1/repos/{owner}/{repo}/logs 会按时间倒序返回队列生命周期事件。queue show 会替你调用此接口,而 mergify events --pr <PR> --since 90d(mergify-events 技能)则会通过命令行查看整个生命周期,包括所有事件类型,而不仅是队列事件。仅当命令行不可用时,或命令行调用失败时(例如上文提到的 403,但令牌有权读取日志),才直接使用 curl:
MERGIFY_TOKEN 必须包含 Mergify 令牌:GitHub 令牌仍可用于调用 Mergify API,但已弃用;而 mergify auth login 存储的凭据位于操作系统钥匙串中,而非环境变量,因此原始 curl 无法使用该凭据。
REPO=owner/repo
PR=1234
FROM=$(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'
{
"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"
}
]
}
解读方式如下:
"events": []/size: 0→ 时间窗口内没有离开队列的事件 → 此 PR 从未入队(或者事件已超出保留期限;见下方的时间窗口规则)。merged: true→ PR 通过合并离开队列,并非出队。merged: false→ PR 已出队;dequeue_code会说明原因(见原因表)。unsuccessful_checks[].details_url→ 失败 CI 任务日志的直接链接。PR 离开队列后,可通过此链接查看 CI 失败情况。
以下两种情况可能导致接口悄无声息地返回空结果:
- 实际上必须提供
received_from。 默认时间窗口为最近 24 小时。上周发生的出队会返回size: 0,且不报错,看起来就和“从未入队”完全一样。务必传入received_from。 - 时间窗口不能超过 93 天(保留期限为 90 天),否则调用会失败,并返回
422 'received_from' and 'received_to' cannot span more than 93 days。
同一接口还支持其他实用筛选条件:&outcome=failure 可将离队事件限制为出队(合并对应 success);省略 event_type 可查看整个生命周期(action.queue.enter、checks_start、checks_end、leave)。
3. Mergify Merge Queue 检查运行
检查运行的标题会直接说明原因,其摘要则是完整的队列报告:
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}'
标题可直接映射到状态,无需解析:
output.title | 状态 |
|---|---|
Dequeued — <reason>(结论为 neutral) | 已出队,标题中包含原因 |
Dequeued from merge queue(结论为 neutral) | 已出队,但原因无法对应到已命名代码;请使用界面 1 |
Merged via merge queue(结论为 success) | 已由队列合并 |
Waiting for queue conditions、Checks …、In merge queue | 仍处于生命周期中 |
注意:检查运行关联的是其生成时对应的头部 SHA。如果出队是由推送(PULL_REQUEST_UPDATED、DRAFT_PULL_REQUEST_CHANGED)触发的,当前头部会有一个新的检查运行,而出队报告则位于之前的 SHA 上。这种情况下请使用界面 1 或 4——界面 1 会显示 SHA(Head SHA / queue_leave_head_sha),因此能让你发现不匹配,而不是陷入这个问题。另请注意,gh pr view --json statusCheckRollup 返回的 title 为 null;请按上文所示使用 gh api .../check-runs。
4. # Merge Queue Status 注释
mergify[bot] 每个队列会话都会发布一条注释,因此读取最后一条。推送代码后,这条注释仍会保留,因此它是 GitHub 端最可靠的信息来源。
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 很重要:此端点每页返回 30 条注释,最新的注释在最后一页。因此,如果不使用它,任何有实际讨论的 PR 上,last 都会悄悄返回过时的状态注释(或不返回任何注释)。--slurp 会将各页收集到一个数组的数组中——因此需要用 .[][] 展平——而且不能与 -q 一起使用,所以筛选操作改由 jq 完成。
其结构依次为:隐藏的 JSON 载荷、时间线、合并条件,然后是 ## Reason、Failing checks:(每项都带有一个 [job log] 链接)和 ## Hint。隐藏载荷无需解析文字即可提供状态:
state 的值为 waiting、checking、frozen、bisecting、merged 或 dequeued。它不包含出队代码——出队代码位于下方 ## Reason 的文字中。
注意:可以在每个代码库中关闭此注释(merge_queue.status_comments: none,或设置为 outcomes,仅用于终态事件)。没有注释并不能证明该 PR 从未进入队列。
取消排队原因及后续操作
dequeue_code 的取值及其对应的操作。引擎会在报告中为每个原因提供相应的 ## Hint;如果代码未列在此处,请查看该提示,而不要猜测。
dequeue_code | 发生了什么 | 后续操作 |
|---|---|---|
PR_MERGED | 已由队列合并 | 无需操作——这是成功状态 |
PR_MANUALLY_MERGED | 在队列外合并 | 无需操作 |
CHECKS_FAILED | 合并提交上的必需检查失败 | 查看 unsuccessful_checks[].details_url,修复 CI。推送修复后,只要条件再次匹配,就会自动重新入队;如果检查结果有偶发性,可原样使用 @mergifyio queue 重新入队 |
CHECKS_TIMEOUT | 条件满足前,checks_timeout 已过期 | 查看原因详情:从未报告的检查意味着条件中的检查名称与 CI 发布的名称不匹配(修复配置,而不是 PR)。仍在运行的检查意味着 CI 太慢或卡住了 |
PULL_REQUEST_UPDATED | 排队期间有人向 PR 推送了提交 | 不要向已排队的 PR 推送。分支定稿后再重新入队 |
DRAFT_PULL_REQUEST_CHANGED | 队列的草稿/批次 PR 收到了 Mergify 未创建的提交 | 切勿推送到合并队列的草稿分支。重新为原始 PR 入队 |
CONFLICT_WITH_BASE_BRANCH | PR 与其基分支存在冲突 | 变基或合并基分支,解决冲突,然后重新入队 |
CONFLICT_WITH_PULL_AHEAD | PR 与队列中排在它前面的 PR 存在冲突 | 等前面的 PR 合并后,再变基并重新入队 |
BRANCH_UPDATE_FAILED | Mergify 无法更新 PR 的头分支 | 查看原因详情,自行更新分支,然后重新入队 |
BASE_BRANCH_MISSING / BASE_BRANCH_CHANGED | 基分支已删除或发生变更 | 将 PR 的目标分支改为仍然存在的基分支,然后重新入队 |
PR_MANUALLY_DEQUEUED | 有人(通过命令、仪表板或 API)将其移出队列 | 原因中会注明是谁以及如何操作的。弄清对方移出队列的原因后再重新入队 |
PR_DEQUEUED | 队列条件不再匹配 | 查看报告中的条件;修复 PR 或重新入队 |
DROPPED_BY_BISECTION_ELIMINATION | 二分排查将问题归咎于其他 PR,因此未经测试便移除了此 PR | 尚未证实有问题,并非已知故障。重新入队,单独测试 |
STACK_PREDECESSOR_DEQUEUED | 同一堆栈中的前置 PR 已被移出队列 | 修复前置 PR,然后重新为整个堆栈入队 |
QUEUE_RULE_MISSING / CONFIGURATION_CHANGED | 已排队的 PR 所用配置发生变更 | 修复 .mergify.yml(参见 mergify-config 技能),然后重新入队 |
INCOMPATIBILITY_WITH_BRANCH_PROTECTIONS | 队列设置与分支保护规则冲突 | 协调仓库的分支保护规则与队列配置——仅重新入队并不能解决问题 |
UNPROCESSABLE_PULL_REQUEST | 检查运行、评论或文件过多,Mergify 无法处理 | 缩小 PR |
并非每个代码都表示 PR 已离开队列。 以下原因会中断检查,但 PR 仍留在队列中——不要将其视为取消排队,也不要重新入队:
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
这些代码会作为 abort_code 出现在 action.queue.checks_end 事件中(并带有 aborted: true),而不是作为离队事件中的 dequeue_code;检查运行标题也会显示 Checks restarted — … 或 Checks aborted — …,而不是 Dequeued — …。判断“它是否真的离开了队列”的权威依据是 merged: false 的 action.queue.leave 事件,而不是是否出现了此列表中的代码。
检查队列状态
使用 mergify queue status 查看合并队列的当前状态:
- 批次:一起接受测试的 PR 组,显示其 CI 状态和预计完成时间
- 正在组建:仍在收集 PR 的批次(
○),显示其队列规则、范围(如果是屏障则显示all scopes)、当前容纳的 PR 数量及规则规定的批次大小,以及最晚开始时间。正在组建的批次尚未在合并顺序中占据位置:它没有 ID,不运行 CI,也不属于批次树。其中的 PR 在queue show中显示Waiting for mergeability check... - 等待中的 PR:已加入队列但尚未进入批次的 PR,显示优先级和排队时间。正在组建批次中的 PR 会列在“正在组建”下;
--json也会在waiting_pull_requests中列出这些 PR - 暂停状态:队列是否已暂停,以及暂停原因
需要以编程方式解析输出时,请使用 --json。
检查队列中的 PR
使用 mergify queue show <PR_NUMBER> 查看 PR 卡住的原因或进展情况:
- 位置:PR 在队列中的位置
- 优先级:匹配的优先级规则
- CI 超时:队列放弃等待 PR 检查的时间(未配置超时则显示
-)——请留意此项,以便在CHECKS_TIMEOUT触发前及时发现 - CI 状态:检查是通过、待处理还是失败
- 条件:已满足的条件和阻塞条件
- 使用
-v(详细模式)查看完整的检查表和条件树
-v 只会列出检查的名称和状态,不包含 CI 作业链接。对于仍在队列中的 PR,如需查看作业日志 URL,请使用上文提到的 GitHub 端入口(检查运行摘要和状态评论);PR 离开队列后,queue show 本身会显示这些链接。--json 会原样透传 API 负载,因此会多出一个人类可读输出中省略的字段:queue_rule(解析后的队列规则配置,而不只是规则名称)。
队列状态
| 状态 | 含义 |
|---|---|
running | 批次正在运行 CI |
preparing | 正在设置批次 |
bisecting | 批次失败,正在通过二分法查找问题来源 |
failed | 此批次的 CI 失败 |
merged | 此批次中的 PR 已合并 |
waiting_for_merge | CI 已通过,正在等待 GitHub 合并 |
waiting_for_previous_batches | 受阻于尚未完成的先前批次 |
waiting_for_batch | 正在等待被选入批次 |
waiting_for_requeue | 前方的批次失败;此批次将重新入队 |
waiting_schedule | 当前不在已配置的合并时段内 |
frozen | 队列已暂停 |
暂停和取消暂停
暂停队列可暂时停止所有合并(例如在发生事故或部署期间):
mergify queue pause --reason "production incident — halting merges"
mergify queue unpause
- 暂停不会取消正在运行的 CI,而是阻止新的合并开始
- 所有团队成员都可以在队列状态中看到暂停原因
- 在脚本中使用
--yes-i-am-sure可跳过确认提示
故障排除
PR 未进入队列:
- 确认 PR 已加入队列:发布
@mergifyio queue,并确认 Mergify 在评论上回复了 👍 - 检查 PR 是否满足合并条件:
mergify queue show <PR_NUMBER> -v - 查看条件部分,确认有哪些要求尚未满足
- 不要假定队列命令从未生效:
queue show会区分已加入后又出队的 PR 和从未进入队列的 PR
PR 在队列中卡住:
- 检查 CI 状态:
mergify queue show <PR_NUMBER> - 如果检查失败,
-v会列出失败项;如需查看作业日志,请阅读# Merge Queue Status评论或Mergify Merge Queue检查运行摘要中的Failing checks:链接 - 如果队列已暂停,请检查是谁暂停了队列:
mergify queue status
PR 从队列中消失:
mergify queue show <PR_NUMBER>— 它会说明 PR 是已出队、由队列合并,还是从未加入队列,并显示出队代码、原因和失败检查的 URL- 绝不要假定“不在合并队列中”就意味着“从未加入队列”:在让任何人重新加入队列前,请先查看标题(或
--json下的dequeued) - 然后根据原因表采取相应操作
队列运行缓慢:
- 检查是否有失败批次触发二分排查:
mergify queue status - 二分排查会逐个测试 PR,因此比批量合并更慢