Git이 무너질 때: 하루 3만 건 머지에서 얻은 모노레포 교훈
극단적인 머지 속도에서 git 모노레포 확장이 실패하는 예측 가능한 방식과, 항상 온라인인 클라이언트 및 서버 측 커밋에서 얻은 교훈을 정리합니다.

git 모노레포를 운영하고 있다면, 언젠가 어딘가에서 상황이 무너지는 지점이 옵니다. Anthropic의 경우 그 숫자는 하루 약 3만 건의 머지, 100GB 규모의 메인 브랜치 히스토리, 그리고 하루 약 2,500만 건의 CI 체크아웃이었습니다. 이를 순진하게 가져오면 git 트래픽이 600페타바이트를 넘습니다. 그것도 매일요. 그들은 5개월 만에 직접 버전 관리 시스템을 만드는 것으로 답했습니다. 여러분의 답이 그래서는 안 됩니다. 다만 그들이 겪은 실수들은 규모가 10분의 1밖에 안 되는 팀에서도 똑같이 반복되는 것을 보니, 그 실수들을 하나씩 짚어 보겠습니다.
실수 1: 중앙집중식 워크플로를 분산식처럼 다루기
Git의 핵심 설계 전제는 분산입니다. 모든 클론이 완전한 저장소입니다. 전체 히스토리, 전체 오브젝트 저장소, 오프라인에서도 완벽히 동작하죠. 이 전제 덕분에 git이 세상을 장악했고, 대부분의 저장소에서는 여전히 맞는 선택입니다. 그런데 거의 아무도 인정하지 않는 사실이 있습니다. 실제로는 거의 아무도 git을 그런 방식으로 쓰지 않는다는 겁니다. 조직에는 GitHub나 GitLab에 권한 있는 원격 저장소가 하나 있고, 개발자들은 끊임없이 push하고 pull합니다. CI 러너는 정의상 항상 온라인이죠. 결국 분산 시스템의 옷을 입은 중앙집중식 시스템을 운영하면서, 분산 시스템의 비용을 치르고 있는 셈입니다. 읽지도 않을 히스토리를 끌어오는 CI 작업이 있고, 필요 없는 packfile을 펼쳐 두는 에이전트 샌드박스가 있습니다.
이것이 Anthropic의 재설계에서 얻은 첫 번째 진짜 교훈입니다. 그들은 한 발 물러서서 살펴본 뒤, 클라이언트가 “정의상 항상 온라인인 에이전트와 작업”이라는 점을 확인하고, 언제나 연결 가능한 서버를 기준으로 설계했습니다. 클라이언트는 의도적으로 단순해졌습니다. 용량이 제한된 로컬 캐시, 디스크의 작업 복사본, 파일시스템 워처만 남겼죠. blame 계산, diff 생성, 머지는 서버가 담당합니다. Google이 Piper에서, Meta가 Sapling에서 내린 결론과 같습니다. 이것은 git을 부정하는 입장이 아니라, 아키텍처를 도구가 20년 전에 설계된 워크로드가 아니라 실제 워크로드에 맞춰야 한다는 인식입니다. 보안 도구에서도 같은 패턴을 봅니다. 오프라인 기능을 갖춘 에이전트 아키텍처를 배포해 놓고, 정작 오프라인이 절대 일어나지 않는 환경에서 돌린 뒤 동기화 계층이 왜 악몽인지 궁금해하는 팀들 말입니다.
여러분 팀이 얻어야 할 교훈은 “VCS를 만들라”가 아닙니다. 가정을 점검하라는 것입니다. 실제로 의존하고 있는 git의 속성을 적어 보세요. 오프라인 작업이 필요한가요? 진짜 포크를 쓰나요? 암호학적 커밋 서명을 쓰나요? 솔직한 답이 “원격 하나, 항상 온라인, CI가 모든 걸 처리”라면, 있지도 않은 분산 워크플로를 위해 최적화하는 일을 그만두고 체크아웃과 쿼리 비용을 최적화하기 시작하세요.
실수 2: 미러와 시드로 규모 문제를 덮어두기
규모가 큰 저장소를 다루는 팀은 누구나 같은 고통의 단계를 거칩니다. 처음에는 shallow clone을 씁니다. 그다음 sparse checkout과 promisor remote를 씁니다. 이후 내부 git 미러를 만들고, 마지막으로 CI 작업이 메인 최신 상태에 가까운 곳에서 부트스트랩할 수 있도록 blob 스토리지에 스냅샷 “시드”를 둡니다. Anthropic은 이 방법을 모두 써 봤고, 최대 시점에는 내부 미러가 수백 개에 달했습니다. 실패 양상도 늘 같습니다. 우회책은 요란하게 터지지 않고 서서히 썩습니다. 시드는 갱신 사이에 점점 메인 최신 상태에서 멀어집니다. partial clone은 git blame과 git log --follow를 헷갈리게 망가뜨립니다. 누군가의 bisect는 히스토리가 잘려 있어서 조용히 잘못된 결과를 내놓습니다. 장애 회고 전까지는 아무도 알아차리지 못하죠.
제가 밤잠을 설치게 만드는 건 바로 마지막 문제입니다. 히스토리 정합성 버그는 바로 그런 미묘한 잘못입니다. 이런 문제는 시스템이 보장한다고 여기는 것과 실제로 하는 일 사이의 간극에 숨어 있죠. shallow clone은 깊이를 넘어서는 blame을 요청해도 에러를 내지 않고, 그냥 부분적인 답을 줍니다. 자동 revert 파이프라인이 그 답을 믿는다면, 틀린 변경을 자신 있게 되돌리는 기계를 만든 셈입니다.
- Shallow clone은 히스토리에 의존하는 도구(blame, bisect, merge-base)를 요란하게 실패시키지 않고 조용히 망가뜨립니다.
- 스냅샷 시드는 메인 최신 상태에서 멀어집니다. 머지 속도가 높을수록 더 빨리 멀어지므로, 부하가 늘어나는 바로 그때 우회책이 무너집니다.
- 미러 플릿은 운영 표면을 늘립니다. 상태를 가진 복사본이 수백 개나 있고, 각각 독립적으로 지연되거나, 손상되거나, 디스크가 가득 찰 수 있습니다.
- 히스토리 의미에 영향을 주는 모든 우회책에는 회귀 테스트가 필요합니다. 없다면 장애 때 반드시 문제를 일으킵니다.
Anthropic 규모에서의 해법은 구조적이었습니다. 서버에서조차 저장소의 완전한 복사본이 어디에도 존재하지 않게 했고, 모든 것을 콘텐츠 주소 기반으로 만들어 수평적으로 캐시할 수 있게 했습니다. 여러분의 규모에서는 해법이 더 소박합니다. 저장소의 전체 또는 거의 전체 복사본을 가진 머신이 몇 대인지 측정하고, 각각이 가진 드리프트와 장애 양상을 솔직하게 직시하세요.
실수 3: 모든 CI 작업이 저장소 복사본을 따로 유지하게 하기
CI 플릿에 대해 던져볼 만한 질문이 있습니다. 작업 중 실제로 작업 복사본이 필요한 것은 몇 개인가요? Anthropic은 시스템을 만든 뒤 “예상보다 훨씬 적다”고 답했습니다. 커밋과 merge base 사이의 diff가 필요하거나, 파일의 blame이 필요하거나, 특정 경로를 건드린 커밋 목록이 필요한 작업은 API로 서버에 직접 물어볼 수 있습니다. 클론도, fetch도, 디스크도 필요 없죠. Anthropic은 자동 bisect와 revert 파이프라인이 이런 저렴한 프로그래밍 방식 접근 없이는 “규모에서 현실적이지 않았을 것”이라고 말합니다. 저도 그 말을 믿습니다. 로컬 클론 위에서 같은 파이프라인을 돌리려다 fetch 시간에 파묻히는 팀을 여럿 봐 왔기 때문입니다.
이 원칙은 소스 관리 너머로도 일반화됩니다. 체크아웃을 기본값이 아니라 비싼 예외로 취급하세요. 작업에 파일이 필요할 때도, sparse 및 가상화된 체크아웃으로 요청된 디렉터리만, 또는 실제로 읽는 파일만 구체화하면 비용을 몇 자릿수나 줄일 수 있습니다. Anthropic의 fetch 프로토콜은 git의 협상 과정을 완전히 제거했습니다. 클라이언트가 원하는 불변 트리와 blob을 특정해서 요청하면, 어떤 캐시든 응답할 수 있습니다. 전체 시스템은 클라이언트마다 packfile을 계산하는 똑똑한 서버가 아니라 계층형 CDN처럼 동작합니다. git 서버가 CI 부하에 녹아내리는 것을 프로파일링해 본 적이 있다면 이게 왜 중요한지 알 겁니다. 프로토콜이 서버에게 각 클라이언트가 이미 가진 것과의 델타를 계산하라고 요구하기 때문에 packfile 생성이 CPU를 많이 먹는 것이니까요.
클라이언트가 항상 온라인이고 권위 있는 복사본이 하나뿐이라면, 여러분이 유지하는 모든 로컬 클론은 전액을 지불하고 있는 캐시입니다. 그리고 어차피 캐시의 의미론만 얻고 있는 거죠.
실수 4: 커밋 비용을 저장소 크기에 비례하게 두기
그들의 설계에서 가장 흥미로운 엔지니어링 결정은 changeset입니다. git 커밋은 저장소 전체 상태를 나타내는 트리를 가리킵니다. 반면 그들의 changeset은 첫 번째 부모 대비 변경된 파일 목록과 blob 스토리지를 가리키는 콘텐츠 주소 포인터만 기록하고, 이를 write-ahead log에 추가합니다. 받아들일 packfile도, 락도, 서버 간 조율도 없습니다. ref(브랜치, 태그)는 의도적으로 비중을 낮췄는데, 이유는 “모든 서버가 합의해야 하는 전역 상태는 골칫거리가 될 확실한 규모 문제”이기 때문입니다. ref 이동은 Spanner 행 하나에 대한 compare-and-swap이며, 커밋 생성과 분리되어 있습니다.

함께 따라오는 아이디어는 “파생 데이터”입니다. blame 인덱스, 경로 히스토리, 커밋 그래프 skip list 같은 것들을 모두 각 changeset의 부모로부터 재귀적으로 계산하고, 하나의 범용 메커니즘으로 처리합니다. 타입에 따라 즉시 계산하거나 지연 계산합니다. 클라이언트를 건드리지 않고도 새 인덱스 타입을 추가할 수 있습니다. 이건 이벤트 소싱 시스템에 정말 좋은 패턴입니다. 감사 로그 파이프라인에도 같은 구조를 추천한 적이 있는데, 추가만 가능한 로그가 진실의 원천이고 모든 쿼리 구조는 언제든 다시 만들 수 있는 프로젝션입니다. 누군가 그 메커니즘 바깥에서 프로젝션을 손으로 관리하기 시작하는 순간 드리프트가 생깁니다.
보안 관점에서 한 가지 단서를 달겠습니다. 중앙집중화를 걱정하는 댓글 작성자들은 진지하게 고려할 가치가 있는 지적을 했습니다. 커밋, 머지, 히스토리 쿼리가 모두 한곳에 모인 단일 서버 시스템은 가치가 큰 표적이 됩니다. 그리고 “모든 것을 지배하는 단 하나의 저장소”에 쓰기 권한을 가진 AI 에이전트는 위험을 크게 집중시킵니다. Anthropic은 이와 함께 “풍부한 소스 컨트롤 IAM 시스템”을 구축했는데, 그 세부 사항이 데이터 구조보다 더 중요합니다. 중앙집중화를 하면 폭발 반경(blast radius) 계산이 달라집니다. 3분기가 아니라 첫날부터 격리, 에이전트별 자격 증명, 감사를 예산에 반영하세요. 공유 인프라에서 상태 유지형 에이전트를 돌리는 팀이라면 이 고통을 이미 알고 있을 겁니다.
실수 5: 하루 3만 건의 머지가 하루 3만 건의 좋은 판단을 뜻한다고 가정하기
엔지니어링은 인상적입니다. 열린 질문은 그 파이프라인으로 무엇이 흘러가느냐입니다. 한 실무자는 이렇게 단도직입적으로 말했습니다. AI가 생성한 코드를 리뷰하지 않을 때마다 “나중에 허접한 결함을 발견한다. 모든 리뷰에서 발견되는 건 아니지만, 자주 발견되니 모든 것을 리뷰하는 걸 멈출 수 없다.” 이 적중률에 하루 3만 건의 머지를 곱해 보면, Anthropic이 “대량의 리뷰된 코드를 관리하고 머지하는 새로운 방법”, 즉 리뷰 표면, 머지 큐, 자동 revert 파이프라인까지 만들어야 했던 이유가 보입니다. VCS가 제품이 아니었습니다. 랜딩 파이프라인이 제품이었습니다. 소스 컨트롤은 리뷰 용량이 먼저 병목이 된 뒤에야 병목이 됐습니다.
그들의 전쟁 일화에 묻힌 솔직한 세부 사항도 있습니다. 프로젝트의 엔지니어들은 자신들의 역할 대부분이 코딩 에이전트에게 “아니오”라고 말하는 것이라고 설명했습니다. 그들이 직접 작성한 프로토타입 수집 파이프라인은 괜찮았지만, 더 새로운 모델이 메모리 사용량은 20배, 속도는 4배 개선된 버전으로 다시 작성했습니다. 다만 그 결과에 도달하려면 무엇을 받아들일지 판단하는 안목 있는 사람이 필요했습니다. 제가 지금까지 본 것과 정확히 맞아떨어집니다. AI는 엔지니어의 일을 작성에서 리뷰로 옮겨 놓았고, 이제 희소한 자원은 리뷰 처리량입니다. 리뷰 단계가 늘어날수록 팀이 느려지는 이유는 전에도 글로 쓴 적이 있습니다. 어려운 점은 에이전트가 만든 코드에서는 리뷰 단계를 줄이는 것도 안전하지 않다는 겁니다. 리뷰를 줄일 게 아니라 리뷰 도구를 더 좋게 만들어야 합니다.
실제로 무엇을 해야 하나
여러분은 Anthropic이 아닙니다. 그들의 토큰 예산도 없고, 하루 2,500만 건의 체크아웃도 없습니다. 하지만 AI 코딩 도구가 모두의 머지 속도를 끌어올리고 있고, 압박 지점은 예측 가능한 순서로 찾아옵니다. 제가 따를 작업 순서는 다음과 같습니다. Priya's Law의 최소 후회 원칙에 따라 정리했습니다:
- 먼저 측정하세요. 하루 체크아웃 횟수, CI 작업당 가져오는 바이트 수, 전체 저장소 복사본을 가진 머신 수를 세세요. 규모 문제보다 낭비 문제가 먼저일 가능성이 높습니다.
- 불필요한 체크아웃을 없애세요. 인프라에 돈을 쓰기 전에, 메타데이터 질문(diff, blame, 조상 관계)을 GitHub/GitLab API나 얇은 내부 서비스로 옮기세요.
- sparse 및 partial clone을 안전하게 만드세요. bisect, blame, revert 도구를 shallow clone 환경에서 명시적으로 테스트하거나, 자동화에서 아예 금지하세요.
- 가능하면 CI 기본값을 서버 측 불변 객체 fetch로 바꾸고, 미러 플릿은 복리로 이자가 불어나는 기술 부채로 취급하세요.
- 저장소 형식이 아니라 랜딩 파이프라인에 투자하세요. 리뷰 용량, 머지 큐, 자동 revert가 에이전트 규모 개발에서 가장 먼저 깨지는 지점입니다.
- 그다음에야 대안 VCS 아키텍처를 고려하세요. Sapling은 오픈소스이며, 직접 만들지 않고도 클라이언트-서버의 이점 대부분을 얻을 수 있습니다.
이 글의 가장 깊은 교훈은 사실 git에 관한 것이 아닙니다. 모든 도구는 워크로드에 대한 가정을 담고 있습니다. 오프라인 사람, 한 번에 하나의 커밋, 리뷰되는 속도보다 느리게 작성되는 코드 같은 가정이죠. 그리고 그 가정들이 지금 인프라, 리뷰, 보안 경계에서 에이전트에 의해 깨지고 있습니다. 앞서 나가는 팀은 모든 것을 처음부터 다시 만드는 팀이 아닐 겁니다. 어떤 가정이 가장 먼저 깨졌는지 알아채고, 바로 그 부분을 정확히 고치는 팀이 될 겁니다.


