PR合并慢,别再只看平均时长:GitHub把等待拆成了三段

文章来源声明: 原文作者:蜗牛聊AI; 来源站点:掘金; 原文链接:https://juejin.cn/post/7689415591787184154; 本文基于上述来源整理/加工,觅优补充点评,仅供技术学习交流。版权归原作者所有。
觅优短评

分段指标把“审查慢”拆成可归因的三段,适合有仓库级权限的研发效能团队做瓶颈诊断。别拿它排个人绩效,先跑四周基线再单点改流程。

一个 PR 花两天才合并,问题可能是没人点开,也可能是修改来回拉扯,或批准后一直搁置。只看总时长会把三种病混成一个数。GitHub 新增的分段指标,让团队能用中位数和 P90 判断该加审查人、缩小 PR,还是改自动合并规则。

这次API增加了什么

GitHub 9 月 25 日宣布,企业和组织的仓库级 Copilot 使用报告新增 pull_request_review_times 数组。每个条目把 PR 生命周期拆成三段:从 ready for review 到第一次审查、第一次到最后一次审查、最后一次审查到合并;每段都提供中位数和第 90 百分位(P90),单位为分钟。

口径非常关键。当前只统计由人创建、且至少被另一名人类审查后合并的 PR;Copilot、其他机器人和作者自己的审查不计入。数据按合并日归属,9 月 21 日之前进入 ready 状态的 PR 不纳入该分段,而且没有历史回填。安静的一天返回空数组 [],不是零。

flowchart LR
    A[PR标记Ready] -->|等待首次响应| B[第一次人工审查]
    B -->|修改与复审| C[最后一次人工审查]
    C -->|批准后等待| D[合并]
    B -.P50/P90.-> E[响应能力]
    C -.P50/P90.-> F[协作复杂度]
    D -.P50/P90.-> G[发布与权限流程]

为什么一定要同时看P50和P90

中位数 P50 代表典型 PR,P90 代表最慢的那一成。若 P50 很短、P90 很长,说明大多数流程没问题,但某些仓库、时区或高风险改动缺少兜底;若两者都长,才更像系统性产能不足。

我的核心判断是:这些指标是排队系统的症状,不是开发者绩效分。拿 P90 给个人排名,会鼓励快速点“批准”、拆成没有意义的小 PR,甚至绕过审查。正确用法是按仓库和变更类型找瓶颈,再验证干预是否降低尾部等待。

最小实践:下载并读取日报

官方接口先返回短时有效的 NDJSON 下载链接,再从报告行里读取数组。下面脚本使用当前文档要求的 2026-03-10 API 版本,密钥只从环境变量读取。

<span>async</span> <span>function</span> <span>main</span>(<span></span>) {
  <span>const</span> token = process.<span>env</span>.<span>GITHUB_TOKEN</span>;
  <span>const</span> org = process.<span>env</span>.<span>GITHUB_ORG</span>;
  <span>const</span> day = process.<span>argv</span>[<span>2</span>] ?? <span>"2026-09-26"</span>;
  <span>if</span> (!token || !org) <span>throw</span> <span>new</span> <span>Error</span>(<span>"缺少GITHUB_TOKEN或GITHUB_ORG"</span>);

  <span>const</span> headers = {
    <span>Accept</span>: <span>"application/vnd.github+json"</span>,
    <span>Authorization</span>: <span>`Bearer <span>${token}</span>`</span>,
    <span>"X-GitHub-Api-Version"</span>: <span>"2026-03-10"</span>,
  };

  <span>const</span> metaUrl = <span>`https://api.github.com/orgs/<span>${org}</span>/copilot/metrics/`</span> +
    <span>`reports/organization-1-day?day=<span>${day}</span>`</span>;
  <span>const</span> meta = <span>await</span> <span>fetch</span>(metaUrl, { headers });
  <span>if</span> (!meta.<span>ok</span>) <span>throw</span> <span>new</span> <span>Error</span>(<span>`GitHub API <span>${meta.status}</span>`</span>);

  <span>const</span> { <span>download_links</span>: links = [] } = <span>await</span> meta.<span>json</span>();
  <span>for</span> (<span>const</span> link <span>of</span> links) {
    <span>const</span> text = <span>await</span> (<span>await</span> <span>fetch</span>(link)).<span>text</span>();
    <span>for</span> (<span>const</span> line <span>of</span> text.<span>trim</span>().<span>split</span>(<span>"\n"</span>).<span>filter</span>(<span>Boolean</span>)) {
      <span>const</span> row = <span>JSON</span>.<span>parse</span>(line);
      <span>for</span> (<span>const</span> item <span>of</span> row.<span>pull_request_review_times</span> ?? []) {
        <span>console</span>.<span>log</span>(<span>JSON</span>.<span>stringify</span>({
          <span>repo</span>: row.<span>repository_name</span>, <span>merged</span>: item.<span>total_merged</span>,
          <span>firstReviewP90</span>: item.<span>p90_minutes_ready_to_first_review</span>,
          <span>reworkP90</span>: item.<span>p90_minutes_first_to_final_review</span>,
          <span>mergeP90</span>: item.<span>p90_minutes_final_review_to_merge</span>,
        }));
      }
    }
  }
}
<span>main</span>().<span>catch</span>(<span>(<span>error</span>) =></span> { <span>console</span>.<span>error</span>(error); process.<span>exitCode</span> = <span>1</span>; });

运行环境需 Node.js 18 以上:GITHUB_TOKEN=... GITHUB_ORG=... node pr-metrics.mjs 2026-09-26。令牌需要组织 Copilot metrics 只读权限,且组织必须启用相应策略。本次无目标组织权限和真实令牌,示例未在本次任务中实际运行;已使用 Node.js 26.7 做静态语法检查。

三种指标对应三种动作

首次审查慢:设置代码所有者和轮值审查人,给高风险目录明确响应时限,而不是群里反复催人。

首次到最终审查慢:查看 PR 尺寸、测试反馈速度和需求是否频繁变化。一个 3000 行 PR 的问题通常不是审查人不努力,而是交付单元太大。

最终审查到合并慢:检查分支保护、部署窗口、必需检查和自动合并。批准后等待很长,往往是机器或权限流程而非代码讨论。

汇总时别把百分位再平均

API 按仓库和作者、审查者类型给出聚合值。把多个仓库的 P90 简单取平均,得不到整个组织的 P90:小仓库的一条慢 PR 会获得与大仓库数百条 PR 相同的权重。若拿不到原始时长,至少按 total_merged 做加权展示,并明确它仍是近似值;更稳妥的是保留仓库维度,分别观察趋势。

还应把“速度”和“质量”并排。审查变快但回滚率、线上缺陷或二次修复上升,不是有效改进。可以为每个仓库同时记录变更失败率、紧急回滚、PR 大小和必需检查耗时。这样才能分辨是审查人响应慢,还是 CI 队列把人类等待伪装成协作问题。

一个可执行的四周实验是:第一周只采集基线;第二周为高 P90 目录设置主备审查人;第三周开启批准后的自动合并;第四周比较三段指标、样本数和失败率。不要同时改十项规则,否则即使数值下降,也无法知道哪项措施有效。

对跨时区团队,分钟数还要结合工作时间解释。周五晚提交、周一审查在日历上很慢,却未必违反团队约定。若产品不提供工作时段口径,可以在自建分析中为每个团队计算“营业分钟”,但要公开时区和节假日规则,避免用不透明修正制造漂亮数字。

风险与适用边界

数据刚开始积累且没有回填,早期样本很薄;单次审查的 PR,“首次到最终”会是 0;total_merged 通常低于仓库全部合并数。小团队每日只有一两个 PR 时,按天的 P90 会剧烈跳动,至少应看四周滚动窗口,并同时保留样本数。

这套指标适合诊断人类参与的审查流程,不适合衡量纯机器人 PR、未合并 PR 的积压,也不能直接证明 Copilot 提升了研发效率。建议先记录四周基线,再一次只改变一项流程,观察三段中哪一段真的下降。

仪表盘之外还要保留定性复盘。每月抽查几条极慢与极快的 PR,问清等待原因、是否有人绕过流程、合并后是否返工。数字负责指出异常,工程师负责解释因果;两者缺一,优化就容易变成追逐指标。

你们团队最慢的一段通常是等第一次审查、反复修改,还是批准后没人合并?

关注「蜗牛聊AI」,一起看懂技术变化背后的真正机会。


本文首发于 java4u.cn,转载请注明出处。