deniz.in

Markets

Weather

Loading weather

· via GitHub Blog

GitHub rebuilt Copilot app diffs to render million-line pull requests

GitHub says the Copilot app's rebuilt diff surface can open a 2,200-file pull request with over a million changed lines and 400 inline comments by splitting layout into two independent geometries.

GitHub rebuilt Copilot app diffs to render million-line pull requests

According to the GitHub Blog, GitHub has rebuilt the diff surface inside the Copilot app so that very large pull requests stay fast and smooth to review. The motivating case is real: broad refactors and migrations often cannot be split into stacked pull requests, which leaves a single enormous change whose review conversation keeps growing. To stress-test the new view, the team opened the largest pull request they could find, an open source change touching 2,200 files, with more than a million changed lines and over 400 inline review comments.

The problem with comments

The post is candid that fast diff rendering is well-understood territory: virtualize the rows, mount only what is near the screen, and recycle DOM elements as the user scrolls. Because every row is a line of code at a known font size, the height table that drives the scrollbar and row positions can be computed entirely up front and never changes. GitHub names this the "all heights known before paint" contract, and the code side of the surface is built around it, using an imperative recycled row renderer, typed-array offset math, diff documents streamed structure-first from the backend, and an imperative scroll-to-row API.

Inline review comments break that contract. You cannot know how tall a comment is until you render it: markdown wraps differently at different widths, sections expand and collapse, a reply composer grows while typing, suggested-change diffs and reactions change size, and images shift the layout when they finish loading. Reserving a fixed-height slot per comment, sized by an estimator, fails at scale. Most comments end up with too much whitespace, the expensive ones clip or sprout a nested scrollbar, and writing a measured height back into the shared offset table moves everything below while the user is already scrolling, producing a large scroll jump.

Two geometries instead of one

The idea that made the problem tractable, according to the post, was refusing to force one geometry to serve both kinds of content. The document's total height is now split into a deterministic code height, the sum of dynamic block heights, and scroll padding. Code geometry stays exact and is never rebuilt when a comment resizes.

Dynamic blocks, which cover review threads, drafts and reply composers, are identified by stable keys anchored to a file, line and side rather than a pixel coordinate, so a reflow cannot lose track of them. Each block carries a fingerprint of everything that could change its height, plus the width bucket it was last measured at, so an ordinary window resize does not invalidate every measurement in the document. A block's effective height falls back from measured to cached to estimated, and the block count scales with the number of comments rather than rows, which the team considers fine at a few thousand as long as first paint does not mount or measure them all at once.

The scheduler they got wrong first

GitHub's first measurement design used one ResizeObserver per block, and the team rejected it during performance hardening. An observer that writes heights back into the layout of the element it watches can retrigger itself, and the cost grows with every mounted block, exactly the feedback loop large virtualized surfaces need to avoid.

What shipped instead is a single measurement pass gated on idle and scroll. It runs once the visible range settles, never once per scroll frame, and waits entirely while a scroll is in flight because a reflow mid-scroll is precisely the jank being avoided. Only blocks within roughly 2,400 pixels of the viewport are candidates, keeping the work proportional to the viewport rather than the document.

The post also names the two other hard problems in this rebuild: the data pipeline feeding the surface, which is useless if it stalls or throws away work it already did, and the difficulty of finding the bugs at all. These issues surface only under load, on a specific engine, at a specific scroll position, so the team defined what healthy meant, instrumented the surface against that definition, and ran the change-measure-improve loop unattended.

Why it matters

Some changes genuinely cannot land as small stacked pull requests, and if the review tool degrades on them, teams are pushed toward weaker review or riskier merges. Beyond GitHub, the post works as a blueprint for anyone building virtualized interfaces with mixed content: keep one layout system for content whose size you know up front, isolate the content whose size you only learn at render time, bound measurement work to the viewport, and validate against realistic extremes rather than synthetic lists. The million-line test case is the point, because performance in review tooling only matters at the sizes where review actually hurts.

  • #github
  • #copilot
  • #code-review
  • #performance
  • #virtualization

Related posts