mcpField
M
mergify-merge-queue

mergify-merge-queue

github.com/mergifyio开发3280 次安装1 天前更新
代码仓库

关于 mergify-merge-queue

通过 PR 评论和 `mergify` 命令行操作 Mergify 合并队列的 Skill。它说明如何监控和诊断队列,包括区分已移出、已合并和从未入队的 PR,并查看失败原因。

主要功能

  1. 01队列状态与 PR 详情命令
  2. 02暂停和恢复队列
  3. 03诊断队列退出状态
  4. 04CI 失败详情与任务日志链接
  5. 05用于检查队列的 JSON 输出

适用场景

  1. 01监控 PR 排位与 CI 进度
  2. 02查明 PR 离开队列的原因
  3. 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 codePR 未合并便离开了队列——参见原因表
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_leave
  • dequeued: 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_BRANCHPR 与其基分支存在冲突变基或合并基分支,解决冲突,然后重新入队
CONFLICT_WITH_PULL_AHEADPR 与队列中排在它前面的 PR 存在冲突等前面的 PR 合并后,再变基并重新入队
BRANCH_UPDATE_FAILEDMergify 无法更新 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_mergeCI 已通过,正在等待 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,因此比批量合并更慢

评论

支持 Markdown