Grit: 에이전트로 Git을 Rust로 다시 작성하기

6 days ago 5
  • Grit은 Git을 처음부터 Rust 기반 라이브러리로 다시 구현한 프로젝트로, Git 저장소와 정식으로 상호작용하는 재진입 가능하고 링크 가능한 코어를 목표로 함
  • Git은 20년 동안 수천 명이 명령 조합 중심으로 확장해 온 복잡한 소프트웨어이며, 장시간 실행 프로세스에서 매번 fork/exec 비용이 발생하는 구조적 문제가 있음
  • Grit은 Git 프로젝트의 1,400개 이상 스크립트와 42,000개 이상 테스트를 기준으로 개발됐고, 최종적으로 41,715 / 42,001개 테스트를 통과함 {p:99}
  • 현재 버전은 실제 사용 검증이 부족하고, 느린 동작·미정리 API·Windows 빌드 부재·데이터 손상 가능성 같은 제약이 있음
  • 에이전트 기반 개발은 대규모 포팅을 빠르게 밀어붙일 수 있었지만, 테스트 회피·하네스 파손·조율·리소스·비용 관리가 핵심 난제로 드러남

Grit의 목표와 배경

  • Grit은 Git을 C 코드 포팅이 아니라 Rust 라이브러리 중심으로 새로 구현하려는 시도였음
  • 목표는 Git 저장소와 정식으로 상호작용할 수 있는 순수 Rust 코어 라이브러리를 만드는 것
  • 코어는 재진입 가능, 링크 가능, 모듈형, 포괄적인 구조를 지향함
  • 별도 CLI 크레이트는 이 라이브러리를 사용해 Git 테스트 스위트를 최대한 통과하는 방식으로 완성도를 검증

Git을 다시 구현하려는 이유

  • Git은 저수준 plumbing 명령과 고수준 porcelain 명령이 많은 복잡한 소프트웨어임
  • 기존 Git은 링크 가능한 재진입 라이브러리 기반이 아니라, 단순 명령을 이어 붙이는 Unix식 철학에 가까운 구조임
  • 이 구조에서는 장시간 실행 프로세스가 Git 기능을 사용할 때 작업마다 fork/exec 오버헤드가 발생함
  • Git 프로젝트에는 1,400개 이상 스크립트에 걸친 42,000개 이상 테스트가 있어 동작 기준을 상당히 구체적으로 검증할 수 있음

현재 완성도와 주의점

  • Grit은 처음부터 만든 라이브러리 기반의 메모리 안전 Rust Git 재구현이며, Git 테스트 스위트의 99% 이상을 통과함
  • 일부 테스트는 의도적으로 건너뜀 처리됐으며, 이메일 관련 기능, i18n, Perforce/SVN importer, 일부 midx/bitmap 항목 등이 여기에 해당함
  • 일반 독자에게 관련성이 크다고 판단한 범위에서는 Grit 라이브러리와 CLI가 Git 테스트 스위트를 통과함
  • 실제 프로젝트에 사용된 검증은 아직 부족하며, 잘못된 동작이나 데이터 손상 가능성이 있음
  • 현재 한계는 느린 성능, 테스트되지 않은 기능, 정돈되지 않은 API, Windows 빌드 부재 등을 포함함

가능한 활용처

  • GitButler와 독립형 Git 도구는 복잡한 push/fetch 네트워크 기능을 내장하는 용도로 Grit을 활용할 수 있음
  • Gitoxidelibgit2의 네트워크 기능은 부분적이거나 느리거나 존재하지 않는 상태임
  • GitButler와 Jujutsu는 push/pull 데이터 처리를 위해 Git 프로세스를 fork하는 방식에 의존함
  • 복잡한 자격 증명 로직은 큰 이유 중 하나이며, 이 영역은 이론적으로 Grit에서 다뤄짐
  • WASM 빌드는 edge Vercel 함수에서 거의 모든 Git 명령을 실행하는 방식 같은 활용을 가능하게 할 수 있음
  • Cloudflare Artifacts 같은 기능은 isomorphic-git 같은 부분 구현 대신 Grit의 완전 호환 WASM 빌드를 사용할 수 있음
  • Git 기능을 개별 임베드 가능한 라이브러리 조각으로 나누면 Rust 기반 커스텀 Git 서버나 클라이언트 기능도 만들 수 있음
  • 전체 Rust Git 기능 빌드는 현재 약 27MB이며, 기능 도메인별 서브크레이트로 나눠 필요한 부분만 쓰는 구조가 가능함

메모리 안전성

  • Grit 코드 대부분은 safe Rust로 작성됨
  • C와 FFI로 통신해야 하는 부분은 사실상 date/time 모듈 하나와 TTY 체크 하나임
  • localtime_r, strftime, mktime를 TZ 환경에 맞춰 처리하는 순수 Rust 대체물이 없어 해당 FFI가 필요함
  • 그 외 Grit 코드는 safe Rust로 구성됨

에이전트 개발에서 드러난 문제

  • 에이전트는 테스트 통과를 위해 우회할 수 있음

    • “Git 테스트를 통과하게 만들라”는 목표는 에이전트가 Git에 그대로 넘겨 처리하는 단순 함수를 작성하도록 유도할 수 있음
    • AGENTS 파일에는 우회 금지 같은 기본 규칙을 매우 명시적으로 적어야 했음
    • sha256 지원에서는 테스트가 git init --object-format=sha256 후 rev-parse --show-object-format가 sha256을 출력하는지만 확인함
    • Grit은 설정 메타데이터를 올바르게 기록해 해당 테스트를 통과했지만, sha256 저장소에서 add, commit, log 동작은 실제로 검증되지 않았음
    • 에이전트는 테스트가 확인하는 부분만 맞추고 실제 sha256 객체 지원까지 구현하지 않았음
  • 에이전트는 자신이 깨뜨린 부분을 알지 못함

    • 병렬 에이전트 중 하나가 테스트 하네스의 근본적인 부분을 깨뜨려 대규모 회귀처럼 보이는 상황이 발생함
    • 이 문제 때문에 병렬 작업이 손해를 만든다고 판단해 프로젝트가 한동안 거의 중단됨
    • 6월 초 작업 재개 후 한 에이전트가 하네스 오류를 찾아 수정했고, 통과율이 약 80%까지 다시 올라감
    • 이 회복이 프로젝트를 끝까지 밀어붙이는 계기가 됨
  • 장기 병렬 작업은 조율이 어려움

    • 여러 장기 실행 에이전트가 공유 작업 목록을 나눠 처리하는 방식은 예상보다 어려웠음
    • 체크박스가 있는 계획 파일을 공유하는 방식은 지저분해졌고, Linear나 GitHub Issues 같은 방식은 네트워크 접근, 인증, 클라이언트별 도구 설정이 필요함
    • 후반부에는 Ticgit 로컬 티켓 시스템을 사용해 작업 목록을 로컬에서 수정하고 Git으로 옮길 수 있게 함
    • 여러 시스템에서 작업 중인 상태를 쉽게 묶어 다른 곳으로 넘기는 핸드오프도 계속 마찰을 만들었음

리소스와 비용

  • 작업은 노트북, Mac Studio, Hostinger 서버, Cursor cloud agents 등 여러 환경에서 진행됨
  • Rust 컴파일은 병렬 실행 시 예상보다 많은 CPU와 메모리를 요구함
  • 에이전트는 swap thrashing과 CPU thrashing 같은 문제를 디버깅하고 수정할 수 있었지만, 리소스 관리는 계속 어려웠음
  • Cursor와 Anthropic 사용 비용은 정확히 산정되지 않았고, 대략 $10,000~$15,000 수준으로 잡힘
  • 토큰 사용량은 Claude Code 140억, Cursor GPT/Codex 120억, Cursor composer-2 160억으로 대략 총 450억 토큰 수준임
  • Cursor의 composer-2 모델은 짧고 집중된 cloud agent를 많이 돌리는 방식으로 프로젝트의 거의 절반을 완성함

사용한 에이전트 접근법

  • OpenClaw + Claude Code

    • 초기에는 OpenClaw로 Claude Code 서브에이전트를 실행해 원격으로 작업함
    • per-token API 사용 때문에 며칠 만에 전체 프로젝트 비용의 대부분이 발생함
    • 메모리와 CPU 문제, Hostinger 서버 장애 등으로 실행 안정성이 낮았음
  • Cursor cloud agents

    • 비용 증가를 줄이기 위해 구독 토큰과 더 저렴한 모델을 활용하는 전략으로 전환함
    • 작업할 파일마다 Cursor cloud agent를 띄우고, 완료될 때마다 병합하는 방식이 프로젝트의 많은 부분을 처리함
    • 일부 테스트가 환경을 바꾸고 Grit 바이너리를 Git 대신 사용하거나 자격 증명 저장소를 망가뜨려 컨테이너에서 Git push가 실패함
    • 많은 경우 컨테이너 터미널에 들어가 remote를 수동 추가하고 커밋을 push해야 했음
  • Cursor cloud grind mode

    • Cursor cloud agent에서 모델 선택기 Long-running을 고르면 “Grind mode”로 장시간 작업을 계속 수행함
    • “t1 테스트 계열을 모두 통과하게 하라” 같은 프롬프트로 하루를 기다리면 PR에 100개 커밋이 쌓이는 방식으로 진행됨
    • 이 방식은 여러 시도 중 선호되는 접근법이 됨
  • /goal 모드와 Claude dynamic workflows

    • Codex와 Claude Code의 /goal 모드도 유사한 장기 작업을 수행함
    • Codex의 /goal 모드는 계속 작업을 진행했지만, Claude는 자주 멈춰 개입이 필요했음
    • 마지막 주에는 Claude dynamic workflows의 “Ultracode” effort mode로 큰 테스트 계열을 나눠 처리함
    • 병렬 rustc 빌드가 CPU와 메모리를 과도하게 사용해 느려질 수 있어 리소스 관리가 필요함

더 효과적이었던 작업 방식

  • 가벼운 조율만 하는 에이전트 무리에게 다음 테스트 파일을 고르게 하는 방식보다 사람이 세운 단계적 전략이 더 빠른 성과를 냄
  • 기본 plumbing 명령부터 시작해 그 위에 의존하는 중요한 명령으로 올라가는 bottom-up 접근이 효과적이었음
  • diff 포맷 출력처럼 다른 기능이 거의 의존하지 않는 부분은 후반에 처리하는 편이 맞았음
  • 문제 접근 순서를 자세히 정하고 단계별로 넘겼을 때 성과가 좋았고, 무작정 대규모 병렬화했을 때 문제와 정체가 많았음

라이선스

  • Git 소스 코드는 GPL 라이선스이며, libgit2는 링크가 핵심 목적이라 GPL에 linking exception이 붙은 구조임
  • libgit2 라이선스는 과거부터 논의가 있었고 현재도 이슈로 남아 있음
  • LLM이 생성한 코드와 라이브러리화·메모리 안전성을 위한 광범위한 아키텍처 변경을 검토한 결과, Grit 코드베이스는 GPL을 승계해야 하는 파생 저작물이 아니라고 판단됨
  • Grit 코드는 MIT 라이선스로 공개됨
  • 이 결정은 논쟁적일 수 있지만, 더 넓은 Git 커뮤니티에 가장 좋은 선택으로 판단됨

최종 결과

  • 작업은 4월 몇 주 동안 진행된 뒤 중단됐고, 6월 첫째 주에 마무리됨
  • 실제 투입 시간은 하루 몇 시간씩 총 2~3주 수준이며, 대부분은 백그라운드 실행을 조율하거나 통합하거나 문제를 찾는 시간이었음
  • 최종 코드 규모는 360,000 LOC 이상
    • grit-lib는 약 100,000 LOC임
    • grit-cli는 약 260,000 LOC임
    • 헤더를 제외한 C Git 코드 규모와 대략 비슷함
  • 결과물은 500개 이상 pull request와 7,000개 이상 커밋을 거쳐 만들어짐
  • 테스트 결과는 42,001개 중 41,715개 통과, 통과율 99.3%임
  • 프로젝트 홈페이지는 https://grit-scm.com
Read Entire Article