프로그래밍 및 소프트웨어 개발

GitHub Copilot이 대규모 풀 리퀘스트 검토 인터페이스를 재구축한 방법

GitHub은 100만 줄을 넘는 변경 사항과 400개 이상의 인라인 댓글이 포함된 팀을 처리하기 위해 GitHub Copilot 애플리케이션의 풀 리퀘스트 인터페이스를 재구축한 과정을 설명한다. 해결책은 미리 계산된 코드 줄의 레이아웃과 동적인 댓글 블록을 분리하고, 점진적인 측정과 사용자의 위치를 유지하는 보정을 적용하는 것이었다.

2026-09-23
4 분 읽기
40 조회수
certi.news Editorial Team
GitHub Copilot이 대규모 풀 리퀘스트 검토 인터페이스를 재구축한 방법

GitHub은 극단적인 상황을 처리하기 위해 GitHub Copilot 애플리케이션의 풀 리퀘스트 표시 인터페이스를 재구축했다. 해당 풀 리퀘스트에는 2,200개의 파일, 100만 줄이 넘는 변경 사항, 400개 이상의 인라인 리뷰 댓글이 포함되어 있었다. 목표는 단순히 대규모 diff 표시를 빠르게 만드는 데 있지 않았다. 대화 자체가 문서에 가변적인 차원을 추가한 이후에도 스크롤과 리뷰를 사용 가능한 상태로 유지하는 것이 목표였다.

대규모 diff를 위한 전통적인 인터페이스는 기본적으로 뷰포트 주변에 표시되는 요소만 유지하고 스크롤하는 동안 DOM 요소를 재사용하는 가상화에 의존한다. 각 요소가 높이를 알고 있는 코드 한 줄일 때 이 모델은 비교적 쉽게 작동한다. 그러나 댓글에는 이러한 특성이 없다. 댓글의 높이는 Markdown 줄바꿈, <details> 섹션 열기, 답글 편집기 표시, 이미지, 제안된 변경 사항, 다양한 상호작용 상태에 따라 달라진다.

하나의 높이 테이블 대신 두 개의 레이아웃 시스템

GitHub은 코드 줄에 대해 고정된 레이아웃을 유지했다. 이 레이아웃은 위치와 높이를 미리 계산하며 댓글이 변경되어도 다시 구축하지 않는다. 반면 댓글, 답글 편집기, 동적 블록은 별도의 인덱스에 배치했다. 각 블록에는 파일, 줄, 측면과 연결된 안정적인 키와 콘텐츠 지문, 열려 있는 섹션의 상태, 마지막 측정 너비가 포함된다.

측정값이 유효하면 측정된 높이를 사용하고, 지문과 너비가 계속 일치하면 캐시된 값을 사용한다. 그렇지 않으면 인터페이스는 임시 추정값을 사용한다. 이에 따라 하나의 댓글이 늘어나도 수백만 줄의 레이아웃을 다시 계산할 필요가 없다.

스크롤 경로 밖에서 수행하는 측정

GitHub은 각 블록마다 별도의 ResizeObserver를 두고 측정값을 레이아웃에 직접 기록하는 초기 설계를 포기했다. 레이아웃 변경이 관찰을 다시 실행하기 때문에 이 방식은 피드백 루프를 만들 수 있으며, 합성되는 블록 수가 늘어날수록 비용도 증가한다.

회사가 출시한 설계는 유휴 시간 및 스크롤이 끝난 뒤와 연결된 단일 측정 주기를 사용한다. 일반적으로 뷰포트에서 약 2,400픽셀 이내에 있는 블록만 측정하고, 먼 블록은 가까워질 때까지 추정값을 유지한다. 반복적인 리플로를 피하기 위해 표시된 요소의 측정값은 한꺼번에 읽는다.

이미지 로드나 답글 편집기 입력과 같은 변경 사항을 감지하기 위해 관찰자는 계속 존재한다. 그러나 높이를 직접 수정하는 대신 블록에 표시를 남겨 다음 측정 주기에서 다시 읽도록 한다. 예외는 섹션이나 답글 편집기를 여는 것처럼 표시된 블록에서 사용자가 일으킨 변경이다. 이 경우 같은 프레임에서 한 번의 동기 보정을 적용할 수 있어 댓글이 늘어난 뒤 그 아래 코드가 이동하는 사이에 눈에 보이는 중간 단계가 나타나는 것을 막는다.

읽기 위치를 잃지 않는 레이아웃 보정

실제 높이가 추정값과 다를 때 인터페이스는 픽셀 수만을 기준으로 위치를 보정하지 않는다. 사용자가 읽고 있는 요소가 줄인지 댓글 블록인지에 관계없이 해당 요소의 정체성을 저장하고, 그 내부의 오프셋을 확인한 다음 높이 차이를 적용하고 동일한 요소의 위치를 다시 계산한다. 이를 통해 고정된 요소는 거의 같은 위치에 유지된다.

일반적으로 사용자가 스크롤하거나 관성을 이용해 이동하는 동안에는 보정을 수행하지 않으며, 화면 아래 콘텐츠에서 발생한 변경으로 뷰를 이동시키지도 않는다. 팀은 패널 너비 변경으로 발생한 프로그래밍 방식의 스크롤을 사용자 스크롤로 간주해 보정이 사라지고 읽고 있던 파일이 어긋나는 버그를 겪었다. 이를 해결하기 위해 사용자 상호작용과 인터페이스 자체가 발생시킨 변경을 분리했다.

자동화된 데이터 경로와 테스트

응답성은 가상화된 렌더링에만 의존하지 않는다. 나머지 문서를 로드하는 동안 파일 트리와 메타데이터가 표시될 수 있도록 diff 구조와 파일 데이터를 먼저 전송한다. 반면 구문 강조와 상세한 Markdown 구성 같은 작업은 요소가 뷰포트에 가까워질 때까지 지연한다. 또한 인터페이스는 최근 사용된 소수의 diff를 일시적으로 유지하고, 그 이상은 제거해 메모리 사용량을 줄인다.

깊은 스크롤에서만 나타나는 결함을 발견하기 위해 GitHub은 지속적인 계측 신호와 자동화된 테스트를 추가했다. 이 테스트는 합성된 행과 블록의 수, 프레임 시간, 스크롤 보정의 크기, 관찰자 누수, 채워지지 않은 빈 공간의 존재를 감시한다. 팀은 데스크톱 애플리케이션과 실제 렌더링 엔진에서 자동화된 흐름을 실행했으며, 섹션 열기, 답글 편집기 실행, 창 크기 변경, 대규모 파일 목록 내 탐색과 같은 상황을 포함했다.

이 설계가 중요한 이유

공개된 결과에 따르면 100만 줄과 수백 개의 댓글이 있는 풀 리퀘스트도 일반적인 풀 리퀘스트처럼 작동한다. 댓글은 중첩된 스크롤 막대 안에서 잘리지 않고 전체 표시되며, 섹션을 확장하면 무작위로 튀지 않고 그 아래의 코드가 이동한다. 또한 풀 리퀘스트로 돌아왔을 때 읽던 위치를 유지할 수 있다. 가장 중요한 공학적 가치는 GitHub이 모든 콘텐츠를 동일한 성격으로 만들려 하지 않았다는 점이다. 결정 가능한 부분은 빠르게 유지하고, 표시하기 전에는 크기를 알 수 없는 콘텐츠와 분리했다.

다만 이 글은 모든 대규모 풀 리퀘스트가 이해나 위험 관리 측면에서 검토하기 쉬워졌다고 주장하지 않는다. 해결한 것은 표시 인터페이스의 성능과 측정 및 변경 과정에서의 동작이다. 또한 결과는 GitHub Copilot과 그 내부 설계에 연결되어 있으며, 다양한 기기와 렌더링 엔진에서의 메모리 사용량이나 성능 지표에 대한 독립적인 수치는 제시하지 않는다.

뉴스 출처
GitHub Blog
원문 보기 ↗
c
작성자

certi.news Editorial Team

같은 카테고리

추천 기사

모든 뉴스 보기