IT 및 AI

에이전트마다 브랜치를 만들면 Git도 빨라질까 - GitHub가 바꾸는 잠금의 단위

푸른강아지 2026. 10. 22. 15:31
반응형

에이전트마다 브랜치를 만들면 Git도 빨라질까 — GitHub가 바꾸는 잠금의 단위

핵심 요약: GitHub는 저장소 전체 쓰기 직렬화를 참조별 직렬화로 좁히는 설계를 공개했습니다. 서로 다른 브랜치의 쓰기는 병렬화하되, 같은 참조의 순서는 지키는 접근입니다. 이는 에이전트를 늘리면 무조건 빨라진다는 뜻이 아니라, 실제로 충돌하는 상태와 독립적인 작업을 구분해야 한다는 뜻입니다.

📌 AI가 코드를 쓰는 속도 뒤에 남는 대기열

여러 코딩 에이전트에게 각자 브랜치를 주면 작업은 자연스럽게 병렬화되는 것처럼 보입니다. 서로 다른 파일을 고치고 각자의 브랜치로 push하니 간섭도 적을 것 같습니다. 하지만 작업 공간이 분리돼 있다는 사실과 저장소 서버가 쓰기를 동시에 처리한다는 사실은 다릅니다. 서버 내부에서 저장소 전체를 잠근다면 독립적인 브랜치도 하나의 계산대 앞에 줄을 서게 됩니다.

GitHub의 agent-scale Git 인프라 설계 글은 바로 이 대기열을 다룹니다. 자체 데이터센터와 Azure에 걸친 복제 과정에서 리전 사이 약 25ms 왕복 지연이 바쁜 저장소의 쓰기 처리량을 제한했다고 설명합니다. 네트워크 지연 그 자체보다, 그 지연 동안 저장소 전체 잠금을 잡고 있다는 점이 문제를 증폭시켰습니다.

이번 설계에서 읽어야 할 핵심은 “클라우드로 옮기니 빨라졌다”가 아닙니다. 어떤 상태의 순서가 반드시 같아야 하는가를 다시 정의했다는 점입니다. 아래에서는 GitHub의 내부 측정과 Git 공식 참조 갱신 문서를 함께 읽고, 호스팅 인프라의 변화가 에이전트 작업 설계에 주는 의미를 구분하겠습니다. 개인 저장소에 새 옵션을 켜서 같은 성능을 얻는 사용법은 아닙니다.

🏗️ 저장소 하나의 줄을 참조별 줄로 나눕니다

설계 축 기존 구조의 제약 공개된 전환 방향
쓰기 순서 저장소 전체 잠금 공유 참조에 충돌하는 쓰기만 대기
리전 간 지연 다른 브랜치의 다음 쓰기도 지연 개별 쓰기 지연은 남되 병렬 진행
읽기·쓰기 자원 같은 복제본의 자원을 공유 객체 저장소를 매개로 독립 확장
확대의 한계 저장소 단일 쓰기 대기열 같은 참조의 경쟁·quorum·읽기 동기화

Git에서 브랜치 이름은 특정 커밋을 가리키는 참조입니다. 같은 브랜치가 어느 커밋을 가리키는지는 일관되게 갱신돼야 하지만, 서로 무관한 브랜치의 갱신 순서까지 하나로 맞출 필요는 없는 경우가 많습니다. GitHub는 이 성질을 이용해 quorum의 직렬화 범위를 저장소에서 개별 참조로 옮긴다고 설명합니다. 공유 참조를 건드리는 쓰기는 기다리고, 서로 다른 참조의 쓰기는 동시에 진행합니다.

중요한 점은 네트워크 왕복 시간이 사라지는 것은 아니라는 사실입니다. 각 쓰기는 여전히 리전 간 통신을 경험합니다. 다만 하나의 쓰기가 통신을 마칠 때까지 다른 브랜치까지 멈추지 않게 됩니다. GitHub는 현실적인 트래픽을 사용한 내부 시험에서 서로 다른 참조의 쓰기 처리량이 3~4배 높아지고 지연도 낮아졌다고 보고합니다. 공급자의 특정 시험 결과이지 모든 push나 개발 작업이 같은 비율로 빨라진다는 보장은 아닙니다.

🔧 객체는 공유해도 참조 갱신의 충돌은 남습니다

Git 객체는 내용을 바탕으로 식별되는 불변 데이터입니다. 같은 내용을 저장할 때마다 누가 먼저였는지 합의해야 하는 가변 레코드와 성질이 다릅니다. 반면 브랜치가 가리키는 커밋은 바뀝니다. 따라서 “커밋 내용을 저장한다”와 “main을 새 커밋으로 이동한다”를 분리해서 생각해야 합니다. GitHub가 조정 비용을 줄이려는 대상도 모든 바이트가 아니라 순서를 보장해야 하는 작은 상태입니다.

Git 공식 update-ref 문서는 새 객체 값과 함께 예상한 이전 값을 지정하면, 현재 참조가 그 이전 값과 일치하는지 검증한 뒤 갱신할 수 있다고 설명합니다. 에이전트가 작업을 시작했을 때 본 상태와 지금의 상태가 달라졌다면 그대로 덮어쓰지 않는 방식입니다. 이 문서가 GitHub의 분산 quorum 구현을 설명하는 것은 아니지만, 참조 갱신에 필요한 조건부 변경의 의미를 이해하는 데 도움이 됩니다.

따라서 에이전트별 브랜치 분리는 독립적인 쓰기 경로를 만드는 데 유리하지만, 최종 통합까지 독립적으로 만들지는 못합니다. 서로 다른 브랜치에서 같은 인터페이스를 모순되게 바꾸거나, 모두 main에 병합하려 하면 다시 공통 상태를 만나게 됩니다. 서버의 잠금 충돌, Git의 이력 충돌, 프로그램의 의미 충돌은 서로 다른 문제입니다. 첫 번째를 줄였다는 이유로 나머지도 해결됐다고 볼 수 없습니다.

🖥️ 읽기를 늘리는 일은 최신 상태를 보장하는 일과 다릅니다

에이전트는 push만 하지 않습니다. 작업 시작 때 저장소를 읽고, 다른 브랜치를 확인하고, 수정 뒤 diff와 상태를 반복 조회합니다. GitHub는 많은 저장소에서 쓰기 한 번당 읽기가 100~1,000번 발생한다고 설명합니다. 읽기와 쓰기가 같은 복제본에서 자원을 나누면, 쓰기 처리량 개선만으로 전체 트래픽 증가를 감당하기 어렵습니다. 그래서 저장과 계산의 분리가 다음 축으로 등장합니다.

공개된 단계에서는 객체 저장소로 쓰기를 전달하는 가상 쓰기 복제본을 quorum에 넣습니다. 이 복제본은 읽기를 제공하지 않으며 쓰기가 객체 저장소에 내구성 있게 저장되도록 하는 역할을 합니다. 이후 가상 읽기 복제본은 객체 저장소에서 캐시를 채우고, 쓰기 quorum에 참여하지 않은 채 읽기를 처리할 수 있습니다. 이는 읽기에 필요한 계산 자원을 별도로 늘릴 수 있게 하는 연결 고리입니다.

그러나 캐시를 늘릴 수 있다는 것과 모든 요청에 최신 참조를 보여준다는 것은 다릅니다. GitHub는 초기 가상 읽기 복제본이 백그라운드에서 상태를 대조하므로 일부 읽기 작업에 적합하며, 모든 유형의 읽기를 제공하려면 변경된 참조와 데이터를 요청 경로에서 동기화하는 후속 단계가 필요하다고 명시합니다. 이를 이미 모든 읽기 최신성 문제가 해결된 완성형 구조로 소개하면 설계의 중요한 한계를 지우게 됩니다.

🧐 냉정한 평가 — 병렬성은 일관성의 반대말이 아닙니다

제 판단으로는 이 설계의 가치는 잠금을 없앴다는 데 있지 않습니다. 지켜야 할 순서를 더 작고 정확하게 정했다는 데 있습니다. 에이전트 수가 늘 때 무조건 큐를 늘리거나 모든 작업을 전역 잠금으로 묶는 양극단보다, 어느 상태를 공유하는지 확인하는 것이 먼저입니다. GitHub 자체도 참조별 전환 뒤에 quorum이 쓰기 확장의 한계로 남는다고 설명합니다. 한 병목을 줄이면 다음 병목이 보이는 점진적 개선입니다.

그렇다고 참조 하나씩의 원자성만으로 모든 업무 요구를 표현할 수 있는 것은 아닙니다. Git 공식 문서는 여러 참조를 함께 수정하는 트랜잭션을 제공하면서도 동시 읽기가 일부 수정만 관측할 수 있다는 주의점을 밝힙니다. 이 동작을 GitHub의 읽기 보장과 동일시해서는 안 됩니다. 오히려 “여러 변경을 함께 성공시킨다”와 “누구나 그 묶음을 하나의 스냅샷으로 읽는다”는 계약을 따로 확인해야 한다는 경고로 읽어야 합니다.

일반 개발팀이 지금 GitHub 내부 구조를 복제할 필요는 없습니다. 작은 저장소에서 병목이 테스트 실행이나 사람 리뷰라면 브랜치를 더 나눠도 체감 이득이 없을 수 있습니다. 반대로 수많은 에이전트가 짧은 변경을 연속 push하는 환경이라면 서버 쓰기와 반복 읽기의 비중이 커질 수 있습니다. 내부 측정의 배율을 그대로 가져오기보다 자신의 대기 시간이 어디서 생기는지부터 확인하는 것이 타당합니다.

🔮 지금 확인할 작업 분해 원칙

  • 독립 브랜치와 독립 책임을 함께 만듭니다. 에이전트별 브랜치만 분리하지 말고 수정 대상과 인터페이스 소유권도 정합니다. 저장소 쓰기는 독립적이어도 같은 계약을 다르게 해석하면 통합 비용은 남습니다.
  • 기준 커밋과 검증 커밋을 기록합니다. 작업 시작 기준과 테스트한 커밋, 최종 통합 대상을 연결합니다. 브랜치 이름은 움직이므로 이름만 기록하면 어느 상태를 검증했는지 불명확해집니다.
  • 공통 참조의 변경은 명시적으로 조정합니다. main 병합이나 릴리스 참조 갱신은 현재 상태 확인과 충돌 처리 경로를 둡니다. 모든 에이전트가 공통 참조를 강제 갱신하게 두면 브랜치 분리의 이점을 스스로 무너뜨립니다.
  • 단계별 대기를 따로 측정합니다. 생성·fetch·push·테스트·병합 대기를 분리해 병렬 수를 조절합니다. 평균 작업 시간만 보면 서버 조정 비용이 줄어든 뒤 통합 대기열이 길어진 사실을 놓칠 수 있습니다.

이 원칙은 GitHub가 제품 기능으로 보장한다고 발표한 체크리스트가 아니라, 공개 설계에서 도출한 작업 운영 제안입니다. 가져올 것은 거대한 인프라 그 자체보다 질문의 순서입니다. 먼저 공유 상태를 찾고, 반드시 지켜야 할 순서를 정의한 다음, 그 밖의 작업을 병렬화합니다. 에이전트 시대의 확장성은 “몇 개를 동시에 돌렸는가”보다 “무엇을 기다리지 않아도 되게 만들었는가”에서 드러납니다.

💡 한 줄 요약: 브랜치를 나누는 것만으로는 부족합니다. 실제로 충돌하는 참조는 순서를 지키고, 독립적인 쓰기는 서로 기다리지 않게 만드는 것이 확장의 핵심입니다.
반응형