나만의 Git을 만들었다

1 week ago 8

  • 버전 관리 시스템의 내부 구조를 이해하기 위해 직접 Git과 유사한 시스템을 구현한 사례
  • SHA-256 해시zstd 압축을 사용해 Git의 SHA-1과 zlib을 대체, .tvc 디렉터리 구조로 저장소 구성
  • Rust로 작성되었으며, 파일 해시·압축·커밋·체크아웃 기능을 단계별로 구현
  • 커밋 객체는 트리 해시, 부모 커밋, 작성자, 메시지를 포함하며, 동일한 파일은 해시 중복 방지로 재저장되지 않음
  • Git이 콘텐츠 주소 기반 파일 저장소임을 직접 체험하며, 구조적 데이터 포맷의 중요성을 강조

해싱과 압축 방식

  • Git은 모든 객체를 SHA-1 해시로 식별하지만, 이 프로젝트에서는 SHA-256을 사용
    • SHA-1은 오래되고 보안상 취약하지만, 이 프로젝트는 단순히 파일 내용을 식별하기 위한 용도이므로 보안성은 중요하지 않음
  • Git의 zlib 대신 Facebook의 zstd 압축 라이브러리를 채택
    • zstd가 더 효율적이라고 판단했으며, Git 호환성은 목표가 아니었음
  • 프로젝트 이름은 “tvc (Tony’s Version Control)” 로, .tvc와 .tvcignore 파일을 Git의 대응 구조로 사용

구현 단계

  • 구현 절차는 명령 인자 읽기 → 무시 규칙 읽기 → 파일 목록 출력 → 해시 및 압축 → 트리·커밋 생성 → HEAD 관리 → 커밋 체크아웃 순서
  • Rust로 작성되었으며, ls 명령은 .tvcignore 규칙을 적용해 비무시 파일을 재귀적으로 탐색하고 각 파일의 SHA-256 해시를 출력
  • zstd 라이브러리를 이용해 파일 압축 및 해제 기능을 간단히 구현

커밋 구조

  • 커밋 객체는 다음 정보를 포함
    1. 객체 유형(“commit”)
    2. 당시 파일 시스템 상태(트리 해시)
    3. 이전 커밋(HEAD)
    4. 작성자(author)
    5. 커밋 메시지
  • Git과 달리 작성자와 커미터 구분을 생략, 병합이나 리베이스 기능은 구현하지 않음
  • 커밋 생성 시 트리 객체를 생성·해시·압축해 .tvc/objects/에 저장하고, HEAD 파일을 갱신
  • 동일한 파일은 해시가 같으면 재저장되지 않아 중복 저장 방지 가능

트리 객체와 체크아웃

  • generate_tree() 함수는 디렉터리를 순회하며 각 파일을 해시·압축·저장하고, 파일명과 해시를 문자열로 구성
    • 하위 디렉터리는 재귀적으로 처리해 트리 구조를 형성
  • 커밋과 트리 객체를 구조체(Commit, Tree)로 파싱해 메모리에서 다루기 쉽게 구성
  • generate_fs() 함수는 트리 구조를 기반으로 파일 시스템을 재생성하며, 지정된 경로에 체크아웃 수행

프로젝트의 교훈

  • Git은 콘텐츠 주소 기반(key-value) 파일 저장소라는 점을 직접 체험
  • 가장 어려웠던 부분은 객체 포맷 파싱이었으며, 다음에는 YAML이나 JSON 같은 명확한 포맷을 사용할 계획
  • 전체 코드는 GitHub 저장소(tonystr/t-version-control)에서 공개
  • 이 프로젝트는 Hacker News 메인 페이지에 소개되어 관련 토론이 진행됨

Read Entire Article