top of page

GitHub Copilot 拉取请求渲染现可处理百万行差异

1天前
讀畢需時 16 分鐘

GitHub 重构了 GitHub Copilot 的拉取请求渲染功能,使其能够打开超过一百万处变更行的差异,而不会让代码审查变成漫长的等待。据该公司的工程团队文章称,其极限测试涵盖了 2,200 个文件和超过 400 条行内评论。

这一规模令人印象深刻,但更重要的是其中的架构冲突。代码行的尺寸可预测,而审查对话会随着用户输入、展开详情、加载图片或调整窗口大小而改变高度。将两者置于同一个虚拟化文档中,可能产生空白区域、被裁切的评论、不稳定的滚动位置以及重复的布局计算。

GitHub 的答案并非打造一个更快的通用列表。团队将确定性的代码几何结构与动态评论几何结构分离,然后测量视口附近的不确定内容。这一选择挑战了前端开发中一种常见的本能:将所有项目强行纳入同一个可复用抽象。

这项工作正值 AI 编程代理在拉取请求工作流中创建和审查更多变更之际。GitHub、GitLab、Bitbucket 及各类专业审查工具,都需要在生成式代码增加审查量时维持可用的界面。渲染已不再只是产品故事的底层环节;它可以决定人类是否能检查代理生成的内容。

GitHub Copilot 拉取请求渲染有哪些变化

GitHub 围绕两种不同类型的内容重新设计了差异界面,而非将整个拉取请求视为一个统一列表。

该公司于 2026 年 9 月 23 日发布了其技术说明。文章称,改版后的 GitHub Copilot 应用可以打开、滚动并与一个异常庞大的开源拉取请求交互。该测试包含 2,200 个文件、超过一百万处变更行,以及 400 多条行内审查评论。

差异是展示不同代码版本之间新增、删除和修改内容的界面。大型差异传统上受益于虚拟化:它只渲染屏幕上可见的小部分内容。浏览器的行为仿佛每一行都存在,但文档实际上只包含数量有限的已挂载元素。

GitHub 表示,其界面一次仅保留大约 100 行真实代码。随着审查者滚动,系统会复用这些元素。其余代码行则以计算出的位置信息存在,而不是单独的文档对象模型节点。

这种技术之所以有效,是因为代码行通常具有可预测的几何结构。在已知行高的情况下,应用无需渲染前面的每一行,就能计算某一行的位置。类型化数组存储紧凑的数值偏移,而命令式渲染器则避免为每一行创建 React 组件。

该公司将其称为“绘制前已知所有高度”的契约。浏览器显示前,每一行代码都有可计算的位置。精确的几何结构支持尺寸正确的滚动条、直接跳转至特定代码行以及可预测的元素复用。

评论却违背了这项契约。Markdown 会因视口变化而以不同方式换行。图片加载后会增加高度,回复框会随输入而变大,而建议修改会引入自身嵌套的差异。可展开的详情可能在审查者已经看到某个线程后改变其尺寸。

单一估算高度无法可靠地表示这些情形。宽松的估算会留下明显空隙,而较小的估算则会裁切内容或产生嵌套滚动条。渲染后替换估算值还会移动其后所有项目,导致读者当前的位置发生跳动。

因此,重构后的界面将代码行和审查线程置于独立的几何域中。代码保留精确、预先计算的坐标系统。动态块则获得稳定的身份标识、估算值、缓存测量结果,以及与代码位置关联的锚点。

文档总高度由确定性的代码高度、动态块的有效高度和滚动留白共同构成。评论尺寸变化时,动态索引会更新,而无需重建每一行代码的几何结构。昂贵计算随附近评论数量增长,而非随总行数增长。

这是第一个重要结果。Copilot 应用并未让一个可变高度虚拟化器吸收所有需求。它保留了专用代码渲染器,并为无法变为确定性的内容建立了一个受限系统。

这一决定也解释了为何百万行这个数字并不只是宣传规模。该架构避免让日常交互成本与总行数成正比增长。如果这一特性成立,极端差异就成为对局部受限工作量的检验,而非对原始文档大小的检验。

为什么行内评论会破坏普通差异虚拟化

最棘手的渲染问题并非百万行代码,而是插入在代码行之间、不断变化的对话。

标准虚拟化列表需要回答两个问题:哪些项目与视口相交,以及这些项目应放置在何处。固定高度的行让这两个问题都可通过简单算术解决。

可变高度虚拟化器使用估算值,并以测量结果替换它们。这种方法适用于许多信息流和长列表。Google 的虚拟化指南同样解释了,渲染有限窗口如何减少浏览器工作量。

代码审查提出了更严格的预期。审查者会在具有语义意义的文件和代码行之间导航。跳动数百像素带来的不只是视觉体验受损,它可能使评论脱离审查者正在评估的代码。

评论也会在初次测量后发生变化。审查者可能打开回复编辑器、展开折叠的诊断信息,或等待嵌入图片加载。每项操作都会产生新的布局,但不会改变评论底层的代码锚点。

GitHub 的动态块通过身份标识解决了这一问题。每个块都关联到文件、代码行和差异侧别,而非固定的像素坐标。系统可以重新计算其位置,同时保留审查者认知中的同一位置。

每个块还携带一个表示高度相关状态的指纹。该状态包括内容、展开的详情以及活跃编辑器状态。应用会记录上一次测量该块时的宽度。

宽度之所以重要,是因为调整尺寸后,换行文本可能增加或减少行数。根据其文章,GitHub 将宽度划分为多个区间。因此,窗口的小幅变化不会立即使所有已存储的测量值失效。

有效高度来自当前最佳可用来源。有效的实时测量结果优先,其次是匹配的缓存测量结果。尚未接近视口的内容则使用估算值。

这形成了从不确定性到准确性的过程。远处内容保持低成本,因为应用不会仅为发现其尺寸而渲染它。附近内容会在误差影响可见体验前变得准确。

这一设计类似于 CSS content-visibility 背后的原则:它允许浏览器跳过屏幕外内容的渲染工作。CSS 属性参考也描述了在内容仍被跳过时使用固有占位尺寸的方式。

GitHub 的需求超出了这项浏览器功能。它必须协调代码行计算、应用级评论状态、精确导航以及用户驱动的更新。不过,两种方法共享一个理念:屏幕外内容应保留足够的几何信息以支持布局,同时无需承担完整的渲染成本。

团队最初考虑让每个动态块通过自己的 ResizeObserver 写入新的测量结果。ResizeObserver 会报告元素渲染尺寸的变化。当内容独立于普通窗口大小调整事件而发生变化时,它非常有用。

这种直接设计带来了反馈风险。观察器可能测量一个块、将其高度写入布局状态、触发另一轮布局,然后再次观察结果。成本会随已挂载块的数量增长。

GitHub 保留了观察器,但缩小了它们的权限范围。默认情况下,它们会将块标记为等待后续测量,而不是立即改变布局。随后,应用会一起读取符合条件的元素,并批量应用修正。

其中有一个狭窄的例外。可见区域内由用户触发的变化,如果应用等待空闲时间,可能看起来像是出了问题。改版后的界面可以测量该块,并在绘制前应用一次同步修正。

GitHub 表示,它将此类同步更新限制为每帧一次提交,也避免在活跃滚动期间执行。因而,一连串变化可以合并为一次调整,而不会在滚动路径中注入重复的重排。

这种区别微妙却很重要。应用仍会观察多种变化,但会集中控制这些观察结果何时能够影响几何结构。测量变成了经过调度的工作,而非不受控制的回调集合。

两套几何结构让百万行差异保持稳定

核心机制将应用能够精确掌握的内容与只能估算的内容分离,并防止不确定性污染整个文档。

确定性域包含代码。其位置来自已知行高和前缀和,前缀和会累计每一行之前的高度。前缀和让应用能够找到后续偏移量,而无需在每一帧扫描此前所有代码行。

动态域包含审查线程、草稿、回复编辑器和其他可变块。这些对象构成的集合远小于代码行。即使是繁忙的审查,评论数量通常也远少于变更行数。

这种分离保留了专用渲染器现有的优势。评论变高时,应用无需重建代码几何结构。它只会更新位于相关代码行之前或附近的动态块所占贡献。

GitHub 将主动测量限制在距视口约 2,400 像素以内的块。这个窗口为系统提供了足够时间,使其在内容可见前以测量值替换估算值。更远的块继续保留估算尺寸。

已挂载内容仍是权威来源。调度器会在一次批处理中读取每个符合条件的已挂载块的渲染高度,读取之间不进行布局写入。这避免了交替读取和写入可能迫使浏览器反复计算的问题。

对于附近但尚未挂载的内容,系统最多允许一次屏幕外渲染尝试。非常高的块甚至可以跳过这次尝试。其多余的估算空间保留在视口下方,较不可能干扰当前工作。

可见结果取决于滚动锚定。在应用新高度之前,应用会按身份记录当前行或块,以及查看者在其中的偏移量。随后它更新几何结构,并将同一锚点解析到新位置。

如果视口上方的内容变高,应用会按相应差值移动滚动位置。正在阅读的内容看起来会保持静止。视口下方扩展的内容则不需要同样的修正。

直接交互会得到不同的处理方式。当审阅者展开一个可见的 details 元素时,界面允许其下方内容自然移动。刻意纠正这种有意发生的移动,可能会让界面显得不够顺畅。

应用还必须区分人为滚动与自身引起的移动。GitHub 曾发现一个 bug:切换文件树侧边栏会改变 diff 的宽度。换行内容随之重排,而界面在稳定过程中产生了一次小幅的程序化滚动。

此前的保护机制将这种移动视为用户正在滚动的证据。于是,它抑制了本应用于保持读者位置的校正操作。正在审阅的文件逐渐偏离了视口。

修复方案将用户输入与应用生成的移动分离开来。这说明了一条更广泛的前端原则:副作用不能可靠地作为用户意图的证明。系统往往会产生与其正在监听的事件相同的可观察结果。

GitHub 的方法更重视身份而非像素。像素描述的是元素在某一种布局下出现的位置。文件、行和评论标识符则描述了审阅者在多种布局中阅读的内容。

这在窗口缩放、侧边栏变化以及评论 hydration 时尤为重要;后者会用真实内容替换加载占位符。每个事件都可能改变数百个后续像素位置,却不会改变审阅者在概念层面的阅读位置。

由此形成的界面旨在保持连续性。评论以完整高度渲染,而非获得内部滚动条。展开一个区域会推动下方代码移动,同时审阅者周围的上下文仍然清晰可理解。

这也是 GitHub 的方案与泛泛的“少渲染一些元素”建议不同之处。公司需要同时支持精确的代码导航与灵活的讨论内容。固定网格和完全通用的信息流都无法完全满足这一要求。

该架构接受受控程度的估算。它并不假装所有尺寸都能在早期获知,而是限制误差存在的范围,在读者附近校正误差,并将这些校正锚定在有意义的对象上。

这正是 GitHub Copilot pull request 渲染更深层的启示。规模来自于维护不同的不变量,而不是将每个对象都塞进同一种抽象。

数据管线与视口同样重要

即使渲染器很快,若数据以错误顺序到达,或已完成的工作在导航时消失,用户依然会觉得应用出了问题。

GitHub 的改动不止于布局计算。应用会增量请求 diff 数据,并在完整内容到达前先流式传输结构信息。文件树和元数据可以先显示出来,而完整文档仍在继续加载。

GitHub 表示,完整的审阅线程位置集合会提前到达。这让几何系统获得稳定的拓扑,即文件、行和评论已知的排列结构。单条评论正文仍可在之后加载。

没有这种拓扑时,新的线程可能会在开始滚动后出现在当前视口上方。插入内容会改变后续位置,并需要进行更大幅度的校正。及早解析位置能够减少这一不稳定来源。

应用还会推迟逐项处理。语法高亮在主界面线程之外运行,因此代码会先以纯文本形式出现。颜色和 token 样式会在结果可用时再到达。

这种排序将高亮视为渐进增强,而非一道关卡。审阅者可以在每个 token 获得最终呈现之前查看和滚动代码。大型 Markdown 正文和建议修改的上下文也遵循类似的近视口策略。

结构与装饰之间的区别,对其他工程界面同样有价值。产品可以先呈现可导航的形态,再添加计算成本高昂的细节。等待完整增强通常会让整个界面继承最慢操作的延迟。

导航又引入了另一项权衡。离开 pull request 后释放大型 diff 文档,可在长时间会话中保护内存。若将每个访问过的 diff 都留在内存中,桌面应用最终会消耗不必要的资源。

但立即移除已完成的 diff,会造成不自然的返回路径。页头和文件树可以从保留的元数据中重新出现,而中央 diff 却仍是空的。围绕缺失内容快速绘制出的外壳,可能比整体都更慢的页面显得更像是出了故障。

GitHub 保留了这一内存策略,但为最近几个 diff 添加了有界缓存。较旧的文档会被逐出,而最近的文档可用于快速返回导航。后台刷新会检查保留内容是否已经过时。

公司没有在工程文章中披露内存预算、缓存数量或时序分布。因此,读者不应将这项极限测试视为通用的性能保证。硬件、操作系统、仓库结构和评论内容都可能带来不同结果。

不过,这种管线设计提供了可信的机制。它无需等待语法高亮完成,防止评论位置在活跃滚动期间陆续出现,并复用有限范围内最近完成的工作。

这些选择也反映了 pull request 角色的变化。Copilot app workflow 让用户可在一个应用中管理 issue、指挥编码工作、审阅 diff 并留下评论。diff 界面已成为更长代理会话的一部分,而非独立页面。

竞争对手也面临同样的产品压力。GitLab 和 Bitbucket 支持大型 merge 或 pull request 工作流,而 Claude Code 和专用审阅代理可以将发现的问题以内联方式呈现。每增加一条自动化评论,都会多出一个需要人类导航的动态区块。

竞争问题并不只是哪个模型能发现更多问题。审阅工具同样要竞争:在输出日益增长的情况下,其界面是否能保持上下文。若显示过程让人疲惫不堪,再多评论也没有多大价值。

构建内部工程系统的团队也面临类似挑战。AI 代理生成代码、说明、日志和审阅笔记的速度,可能快于人们评估它们的速度。可搜索的工程知识库能够保留支撑性上下文,但最终的代码决策仍集中发生在审阅界面中。

GitHub 的架构促使竞争开发者工具将渲染视为工作流基础设施。大型 diff 在迁移和大规模重构期间一直存在。代理生成的变更则使其出现频率及其周边讨论变得更加重要。

自动化测量取代了视觉调试

GitHub 将渲染健康状态视为可测量的应用状态,随后构建了一个无需人工值守的循环,可在真实桌面引擎上复现故障。

大型文档 bug 往往出现在特定的滚动位置、宽度、加载状态或引擎时序下。空白条带可能在审阅者滚动离开再返回后消失。这使截图适合用于报告问题,却不足以用于诊断。

GitHub 为 diff 界面添加了永久性的结构化探针。这些探针报告已挂载的行和评论区块数量、测量是否合并为一次提交,以及相关帧所需的时间。

这些埋点还会记录滚动校正的幅度。它会检查滚动开始后是否有评论区块出现,并检查区块卸载时观察器是否断开。这些信号描述的是不变量,而非孤立的视觉症状。

不变量是系统预期应持续为真的条件。在这里,工作量应受视口限制,测量应保持合并,非活动元素不应继续保留观察器。

团队在端到端测试中,将这些条件作为预算进行断言,测试使用了包含大量评论的合成 fixture。持续集成便可发现回归,无需等待某个人遇到极端 pull request。

GitHub 创建了两条自动化测试路径。一条无头路径针对 mock server 执行声明式序列:打开 pull request、滚动至选定比例、切换 details,并调整窗口大小。

该路径收集 React 渲染计数、浏览器性能时序和 requestAnimationFrame 卡顿样本。RequestAnimationFrame 让代码能够与浏览器的显示周期协调工作。回调之间的延迟可以揭示遗漏或缓慢的帧。

该流程在运行时以 JSON 表示。GitHub 表示,代理可以用自然语言描述性能分析序列,无需修改源代码。系统随后执行埋点、运行、收集、分析和瓶颈排序。

第二条路径则在重复循环中控制真实桌面应用。它测试了带评论骨架屏的冷加载,以及带真实内容的热加载。它还会打开回复编辑器、展开文件、切换侧边栏并调整窗口大小。

每个样本都带有健康结果。只有当评论不存在未填补空隙、没有区块保持空白,且真实线程内容在整个滚动范围内都已挂载时,热运行才算通过。

这种方法将性能调试变为可观察的控制循环。首先,系统无需人工即可复现行为。接着,它通过稳定信号而非主观视觉判断来检测故障。

工程师随后可以在可疑边界处添加一个范围有限的探针。在识别出被违反的不变量后,他们保留持久检测器,并移除临时诊断脚手架。

重要的变化并不在于 AI 代理参与其中。自动化之所以有用,是因为应用暴露了可信赖的内部信号。对于无法代表用户可见健康状况的测量,代理也无能为力。

这与基准测试表演形成了有益对照。GitHub 的文章并未聚焦于单一加载分数或单一滚动帧率,而是描述了与缺失评论、空白区域、观察器清理和意外插入相关的条件。

这些指标将实现行为与审阅者体验联系起来。较低的平均帧耗时,无法为永远不出现的线程开脱。快速的初始绘制,也无法修复窗口缩放后失去位置的视口。

该方法还能降低对手动插入日志的依赖。临时日志可能改变时序、遗漏重要状态,或在一次调试会话后消失。永久探针为开发者和自动化系统提供了面对反复出现故障的共同语言。

GitHub 发布的证据仍来自 GitHub 自身。公司尚未提供独立基准测试套件、可复现 fixture,或与竞争客户端的对比。架构细节相当充分,但性能结果仍属于第一方主张。

这一限制并不否定这项工作。它界定了读者应得出的结论:GitHub 解释了一种可信的架构和广泛的内部验证流程,但并未确立一项通用的行业基准。

百万行测试未能证明什么

打开一个极端 pull request 表明该设计能够跨越一个显著边界,但并不能证明它在日常仓库中都具有完全相同的性能。

无论从何种实际标准来看,报告中的测试都异常庞大。其 2,200 个文件和超过 400 条内联评论同时对确定性行与动态区块施加压力。然而,单个 pull request 无法代表所有困难的内容模式。

一百万行短代码与较少但大量换行的代码,可能呈现出不同的行为。包含大量图片、复杂建议修改或深层嵌套标记的评论,也可能产生不同的测量成本。

设备能力同样重要。GitHub 没有公布这项极限测试所用的处理器、内存、显示器或操作系统细节。该文章同样没有提供加载、交互延迟、内存占用和丢帧情况的百分位测量数据。

因此,这一说法应保持准确。GitHub 表示,改版后的 Copilot app 能像处理普通规模的 pull request 一样打开并处理测试中的 pull request。这并不等同于保证它在每一台受支持设备上都具有一致的性能。

该界面也无法解决超大变更的社会成本。即使一个百万行 diff 响应迅速,人类依然很难理解它。渲染消除了一个障碍,却无法降低认知负担,也不能证明变更是安全的。

GitHub 承认,堆叠式 pull request 通常能让审查更容易。一些迁移和大范围重构无法被清晰拆分,这让大 diff 界面具备了正当用途。但例外不应演变成默认的审查策略。

AI 编程提高了风险。智能体可以产出大范围变更,自动化审查工具也可能添加大量评论。更快的渲染或许有助于团队保留人工监督,但也可能让难以管理的大型提交显得更容易被接受。

相关的产品张力在于能力与审查纪律之间。必要的迁移不应因为规模巨大而导致界面失效;团队也不应将界面容量视作审查者能够吸收无限变更的证据。

评论质量还存在另一层不确定性。渲染数百个讨论线程可以确保它们仍可访问,但可访问并不意味着每一条自动化发现都有价值。审查者依然需要优先级、来源和置信度信号。

近期关于智能体生成审查评论的研究,考察了开发者是否会根据这些发现采取行动,以及响应模式有何差异。这类研究突出了另一个问题:即便界面保持响应,增加审查量仍可能制造噪声。

因此,对 GitHub Copilot pull request 渲染能力最恰当的解读应更聚焦,也更有价值。该公司隔离了一个棘手的系统问题,并从其桌面审查工作流中移除了一个技术上限。

它并没有解决超大变更管理、审查者疲劳,或 AI 生成代码的可靠性问题。这些仍是超出视口几何范畴的组织与分析挑战。

有三个信号能够表明,这次重新设计是否超越了工程演示而真正产生意义。第一个是在各类大型 pull request 上保持持续性能,尤其是包含大量换行、图片和活跃讨论的 pull request。

第二个是 GitHub 是否会提供更清晰的性能预算或诊断信息。可复现的测量结果将帮助企业团队了解其自身硬件和仓库模式下的预期表现。

第三个是竞争对手的反应。如果其他审查客户端开始强调大 diff 导航、受限的评论渲染,或保留滚动位置身份,GitHub 的架构就将改变产品预期。

对开发者而言,眼下的行动很简单:用 Copilot app 测试一个令现有工作流感到痛苦的 pull request,然后评估的不只是打开速度。调整窗口大小、重新访问文件、展开评论、在线程内回复,并在离开后再返回。

观察内容是否仍然附着在你正在阅读的代码上。留意空白区域、被裁切的讨论、延迟插入的线程和位置漂移。这些现象比标题中的行数更能说明问题。

对于工程负责人而言,应询问你的审查系统是否像衡量原始延迟一样谨慎地衡量可见的正确性。GitHub 最有力的理念并非百万行演示,而是让布局不变量变得可观测且可持续测试的决定。

响应迅速的界面无法让百万行审查变得轻松,但它可以避免让工具本身增加审查难度。这正是 GitHub 新 diff 界面如今邀请其他开发者平台达到的务实标准。

 
 

免费开始使用

一款本地优先的AI助手

为了获得更好的人工智能体验,

remio 目前仅支持Windows 10+ (x64)和M-Chip Mac 。

你的 AI 工作伙伴

和 remio 一起高效工作

规划、创作、交付

一站式完成

bottom of page