Ayo GitHub Quietly Killed the Unreviewable Mega-PR
If you've ever opened a PR with 47 changed files and a diff so long GitHub just gives up and shows...
개요 #
파일 47개가 바뀐 PR을 열었더니 GitHub이 diff 렌더링을 포기하고 "Load Diff" 버튼만 열일곱 개 띄우는 상황. GitHub이 여기에 손을 댔다. 스택형 풀 리퀘스트(stacked pull requests)를 정식 기능으로 올린 것이다.
핵심은 거대한 변경 하나를 서로 의존하는 작은 PR들의 사슬로 쪼개는 것이다. 각 PR은 자기가 새로 만든 diff만 리뷰 대상으로 보여준다. 아래 단계의 변경 내용까지 통째로 다시 보여주지 않는다.
큰 PR이 리뷰를 망치는 이유 #
2,000줄짜리 diff를 끝까지 꼼꼼히 읽는 사람은 없다. 원문 작성자는 LiveReview 같은 AI 코드 리뷰 도구로 부담을 덜기도 한다고 밝히면서도, 사람이든 모델이든 리뷰 품질은 diff가 짧고 초점이 분명할 때 더 좋아진다고 지적한다. 입력이 작아야 리뷰가 좋아진다는 것, 리뷰어가 누구인지와 무관한 이야기다.
스택의 규칙은 두 줄이면 끝난다 #
같은 저장소 안에 PR이 둘 이상 있고, 다음 조건을 만족하면 스택이다.
- 맨 아래 PR은 트렁크 브랜치(보통
main)를 향한다 - 그 위의 모든 PR은
main이 아니라 바로 아래 PR의 브랜치를 향한다
스키마나 공용 타입처럼 기반이 되는 코드가 아래로, API 라우트나 UI처럼 그것에 의존하는 코드가 위로 간다.
놀라운 부분은 그다음이다. 특별한 도구 없이 순수 git으로 PR #11을 main이 아니라 PR #10의 브랜치에 열기만 해도, GitHub이 이걸 스택으로 알아서 인식한다. base 브랜치가 사슬을 이룬 것을 감지해 배너를 띄운다. 스택은 git 개념이 아니다. 이미 만들고 있던 브랜치 위에 GitHub UI가 얹은 개념이다.
Photo by Myburgh Roux on Pexels
실제로 만들어본 기록 #
원문 작성자는 자신이 관리하는 터미널 파일 브라우저 저장소 peektea에서 임시 파일로 스택을 직접 만들어봤다. 먼저 CLI 확장을 써보려 했지만 이렇게 막혔다.
$ gh stack --help
unknown command "stack" for "gh"gh stack은 CLI 확장이나 더 최신 버전의 gh가 필요하다. 작성자의 환경은 이 기능을 아직 모르는 Ubuntu apt 저장소에서 설치한 버전이었다. 그래서 문서에 나온 "구식" 방법, 즉 확장 없이 순수 git 브랜치를 base끼리 연결하는 방식으로 진행했다.
git 입장에서는 브랜치 세 개가 층층이 쌓인 것, 그 이상은 아니다. 마법은 푸시하고 나서 올바른 base로 PR을 열 때 시작된다.
$ git push -u origin stack/01-setup-database stack/02-api-endpoints stack/03-setup-frontend
$ gh pr create --base master --head stack/01-setup-database \
--title "demo: setup database layer"
https://github.com/lovestaco/peektea/pull/10
$ gh pr create --base stack/01-setup-database --head stack/02-api-endpoints \
--title "demo: add api endpoints"
https://github.com/lovestaco/peektea/pull/11
$ gh pr create --base stack/02-api-endpoints --head stack/03-setup-frontend \
--title "demo: setup frontend"
https://github.com/lovestaco/peektea/pull/12PR #11의 --base가 master가 아니라 stack/01-setup-database라는 점. 이 플래그 하나가 전부다.
GitHub이 알아서 알아본다 #
작성자는 어딘가에서 설정을 켜야 할 거라 예상했다고 한다. 그런데 사슬의 맨 위 PR을 여는 순간 GitHub이 배너를 띄웠다. "This pull request can be stacked with other pull requests"라는 문구와 "Preview stack" 버튼이 함께.
버튼을 누르면 사슬 전체를 위쪽 PR부터 main까지 순서대로 짚어주는 미리보기가 뜬다. 올바른 순서, 올바른 연결. base 브랜치를 제대로 지정해 PR을 연 것 외에는 어떤 설정도 하지 않았다.
"Create stack"을 누르면 목록의 모든 PR에 1/3, 2/3, 3/3 같은 진행 배지가 붙는다. PR 목록 화면에서 바로 보이므로, 어떤 PR이 스택의 몇 번째 층인지 하나씩 열어보지 않고 파악할 수 있다.
GitHub 공식 문서에 따르면 사슬 전체가 만족스러운 상태가 되면 "merge stack" 동작으로 아래부터 순서대로 전부 머지할 수 있다. 머지 사이사이 수동 리베이스가 필요 없다. 작성자는 데모 저장소에서 이 버튼까지는 눌러보지 않았지만("블로그 글 하나에 브라우저 탭 네 개 닫는 것으로 충분한 혼돈"), 문서와 UI 모두 기존의 순차 머지 N번 + 리베이스 N번을 버튼 하나로 대체한다고 가리키고 있다.
원래도 되던 일 아니었나 #
절반은 맞다. 다른 PR의 브랜치를 향해 PR을 여는 것 자체는 새롭지 않다. git과 GitHub의 base 브랜치 드롭다운만 있으면 됐고, 사람들은 10년 넘게 브랜치를 이렇게 이어붙여 왔다.
새로운 것은 GitHub이 그 관계를 이해한다는 점이다. 일급 객체로 추적하고("Create stack"을 누른 순간 스택 ID가 부여됐다), 목록 화면 전체에 진행 상황을 보여주고, 층마다 반복하던 머지-리베이스-머지 수작업 대신 머지 동작 하나를 준다.
git 자체에 스택형 PR 프리미티브가 생긴 건 아니다. 바뀐 쪽은 GitHub UI다. 저장소를 클론해서 브랜치를 들여다보면 다른 기능 브랜치와 조금도 다르지 않다. 스택은 GitHub 쪽에 남아 있는 메타데이터로만 존재한다.
작성자가 진짜 반가워한 이유는 봇 때문이다 #
원문에서 가장 힘이 실린 대목이다. 큰 작업을 맡기고 몇 시간 동안 방치했을 때 Claude 같은 에이전트가 내놓는 결과는 지금까지 둘 중 하나였다. 리뷰가 사실상 불가능한 초대형 PR 하나, 아니면 서로 무슨 의존 관계인지 알 수 없는 연결되지 않은 PR 열두 개.
스택형 PR은 세 번째 선택지를 준다. 신중한 사람이 하듯 리뷰 가능한 층으로 나눠 기능을 쌓고, 의존 사슬 자체가 순서를 말해주게 하는 것. 스키마부터, 그 스키마가 필요한 API, 다시 그 API가 필요한 UI 순서로. 에이전트가 만든 순서 그대로 리뷰하면 된다.
"리뷰 불가능한 3,000줄 PR 하나"와 "서로 관계가 보이지 않는 PR 열두 개" 사이에서 고민할 필요가 없어진다. 스택이 곧 에이전트가 문제를 풀어간 사고 과정의 변경 기록이 된다.
Photo by Christina Morillo on Pexels
지금 도입할 만한가 #
이미 작업을 작은 PR로 손수 쪼개고 리베이스 고통을 감내하는 팀이라면, 습관은 그대로 두고 고통만 사라진다.
"기능 하나에 PR 하나, 크기 상관없이" 방식으로 일하는 팀에게도 진입로가 된다. 지금처럼 이전 브랜치에서 갈라져 나오는 작업 방식을 유지하면서, 머릿속으로 하던 장부 정리를 GitHub에 넘길 수 있다.
GitHub 문서에서 아직 신규 기능으로 분류돼 있으니 거친 부분은 예상해야 한다. 작성자의 gh CLI는 명령어 존재조차 몰랐다. 반면 웹 UI 쪽은 첫 시도부터 설명 그대로 작동했다. 설정도, 옵트인 플래그도 없이 올바른 base 브랜치로 PR을 열면 GitHub이 점들을 이어준다.
CLI 확장 경로를 시도할 생각이라면 gh를 먼저 업데이트하는 편이 좋다.
이 글은 위 출처를 바탕으로 한국 독자를 위해 재작성한 기사입니다. 원문의 사실과 수치에 근거하며, 별도의 견해를 포함하지 않습니다.

