Git 커밋 하나는 얼마나 클까요?

How big is a Git commit?

ratfactor.com ▲ 81 댓글 34 theanonymousone

요약

Git 커밋은 아주 작은 변경에도 수 KB가 들지만, 큰 파일은 원래 크기의 10~50%로 저장합니다.

개발자 데이브 가우어가 개인 사이트의 메모 모음에 올린 실험 기록입니다. 객체를 하나씩 따로 저장하는 기본 상태에서, 커밋할 때마다 .git 폴더가 몇 바이트 늘어나는지 du 명령으로 직접 쟀습니다.

왜 중요한가

  • 커밋 하나의 비용은 바뀐 바이트 수보다 그 파일이 속한 디렉터리 구조에 더 크게 좌우됩니다.
  • 압축이 잘 되는 텍스트라면 아주 큰 파일도 부담이 적어, Git이 공간을 매우 효율적으로 쓴다는 점을 숫자로 보여 줍니다.
  • 팩파일(여러 객체를 묶고 중복을 덜어 낸 저장 형식)을 쓰지 않은 값이라, 실제 저장소에서는 더 작아질 수 있습니다.

핵심 내용

  • 파일 50개가 든 디렉터리에서 3바이트만 바꾼 커밋도 약 17KB를 더했습니다.
  • 파일 하나를 바꾸면 커밋, 트리 2개, 블롭(파일 내용) 등 객체 4개가 새로 생기고, 각각 디스크의 4KB 블록을 차지합니다.
  • 파일 하나뿐인 저장소에서 같은 변경을 하면 약 8KB로, 앞 실험의 절반이었습니다.
  • 16MB짜리 리눅스 커널 헤더 파일은 약 1.6MB, 약 584KB짜리 LibreWolf 실행 파일은 약 300KB만 늘렸습니다.
  • 빈 저장소를 git init으로 만들기만 해도 .git 폴더는 약 64KB였습니다.

HN 반응

  • 여러 이용자가 실험 속 같은 내용의 파일 250개는 블롭 하나로 저장되고, 팩파일의 델타 압축(차이만 저장하는 방식)을 쓰면 더 줄어든다고 보충했습니다.
  • 글의 du 명령에 짧은 옵션 대신 긴 옵션을 써야 읽기 쉽다는 지적이 나왔고, 운영체제마다 옵션이 달라지는 문제를 두고 어느 쪽이 더 안전한지 의견이 갈렸습니다.

댓글

30개 표시 · 전체 34개
  1. cocoto HN

    du 옵션은 요약하는 s와 바이트로 표시하는 b입니다.

    사소한 트집인데, 긴 옵션을 쓰면 코드 예제가 설명 없이도 이해돼요!

  2. analog_daddy HN

    이거 제가 제일 질색하는 것 중 하나예요! 짧은 옵션으로 쓴 셸 스크립트는 읽기가 정말 싫어요. 셸에서 대화형으로 쓸 때야 짧은 옵션도 괜찮지만, 다른 사람이 읽을 스크립트라면 시간을 들여 긴 옵션으로 바꿔 주지 않을 변명이 없어요. 어차피 옵션을 설명하는 주석을 달아야 한다면 더더욱요. 가장 싫은 건 어떤 유틸리티에는 긴 옵션 대응이 아예 없다는 거예요!

  3. seanwilson HN

    또 하나 골치 아픈 건 긴 옵션이 없어서 짧은 옵션을 주석으로 설명하고 싶은데, bash에는 인라인 주석이 없고 여러 줄로 나눈 명령은 한 줄에 주석을 달면 깨진다는 거예요. https://stackoverflow.com/questions/9522631/how-to-put-a-line-comment-for-a-multi-line-command 같은 어색하고 장황한 우회법이 있긴 한데, 다른 팁 있으면 알려 주세요!

  4. zetanor HN

    반대로 모든 사람이 GNU coreutils를 쓰는 것은 아닙니다(저는 Git을 돌리는 모든 머신에서 쓰지만요). 저도 방금 매뉴얼을 읽기 전까지는 du -c와 du --total이 완전히 호환된다고 확신하지 못했을 겁니다. Git이라면 git -m 대신 git --message를 자신 있게 쓸 수 있었겠지만, 그러면 많은 Git 사용자가 놀랐을 겁니다("이게 -m인가?").

  5. saghm HN

    짧은 옵션이 딱히 더 이식성이 좋다고 보기는 어렵다고 생각합니다. 몇 년 전에 CI 문제를 디버깅한 적이 있는데, 원인은 base64 디코딩용 짧은 옵션을 하드코딩한 스크립트였습니다. GNU 버전과 BSD 버전에서 호환되지 않았거든요(한쪽은 -d, 다른 쪽은 -D였는데 어느 쪽이 어느 쪽인지는 기억나지 않고, 솔직히 그게 바로 같은 문제입니다). 새로 추가된 MacOS 작업을 고치던 중이었고, MacOS와 Linux를 구분해서 확인해야 하나 고민하다가 둘 다 긴 옵션으로는 --decode를 쓴다는 것을 알게 됐습니다. 처음부터 긴 옵션을 썼다면 그 문제는 애초에 생기지 않았을 겁니다.

  6. reilly3000 HN

    GPT 이전 시절 데브옵스에서 정말 끔찍한 오후를 보내고 나서 이걸 추가하게 된 일이 떠오르네요.

    
    if [[ $OSTYPE == “darwin” ]]; then
    
    

    alias sed=gsed

    
    fi
    
    

    Mac에서 brew install gnutools를 실행해 두었다면, 이렇게 해서 Linux에서 돌아가는 스크립트를 로컬에서 개발할 수 있습니다. Apple의 BSD sed 포크는 이상해요.

  7. yjftsjthsd-h HN

    모든 짧은 옵션이 이식 가능한 것은 아니지만, POSIX 옵션은 전부 짧은 옵션입니다.

  8. saghm HN

    제 요점은, 표준이 제가 하는 일을 충분히 다루지 않는다면 표준이 뭐라고 하든 별로 신경 쓰지 않는다는 겁니다. 그리고 실제로, 긴 옵션 때문에 스크립트가 실행 환경과 맞지 않았는데 짧은 옵션이었다면 맞았을 경우는 단 한 번도 기억나지 않습니다.

  9. NetOpWibby HN

    저는 가능하면 늘 긴 옵션을 써요. 간결함은 제게 필요 없고, 컴퓨터가 필요로 하는 거죠. 저는 미래의 제가 이걸 어떻게 실행하는지 알아내도록 돕고 싶거든요.

  10. nathanpankon HN

    저는 워크플로에 맞춰 간소화한 Git 대안을 만들어 본 적이 있습니다. 완전히 접은 건 아니지만, 핵심 아이디어는 AST 경로를 이용하면 데이터를 더 압축할 수 있다는 것이었습니다.

    말씀하신 대로 Git은 정말 효율적입니다. 저는 크로미움이라는 (엉망진창인) 작업물과, 전체를 다시 빌드하지 않고 버전 사이의 문제를 고치느라 깊이 파고들었던 경험 때문에 비판적인 시각으로 시작했지만요.

    결국 압축 대안으로서 제 접근법은 가치가 없다는 결론에 이르렀습니다. Git이 더 잘했습니다!

    아무튼 제가 시도한 결과물은 이겁니다: https://github.com/pankon/gat

  11. Anduia HN

    정말 흥미롭네요! AST는 압축보다 diff나 병합에 더 쓸모가 있을지도 모르겠어요.

  12. nathanpankon HN

    이런 시도가 몇 가지 있고(semanticdiff 등) 아주 좋아 보입니다. 하지만 제가 찾던 것은 정해 둔 코드 부분을 적극적으로 편집하면서, 계속 움직이는 대상 위에서 작은 diff를 유지하는 도구였습니다.

    그런 경우에는 "main"에서 병합해 오는 일이 극도로 어려워집니다.

  13. Anduia HN

    공개된 게 아니죠?

  14. nathanpankon HN

    좋은 지적이네요, 공개로 바꿨습니다 :)

    감사합니다!

  15. alansaber HN

    그나저나 이름 좋네요 ㅋㅋ

  16. jamesblonde HN

    Git은 로컬 파일 저장소를 전제로 설계되었기 때문에 분산 파일 시스템에 데이터를 저장하기가 까다롭습니다. 저희는 S3에 데이터를 저장하는 분산 파일 시스템 HopsFS를 만들었습니다. FUSE에서 고성능 Git을 지원하기 위해, 쓰기는 원격 NVMe 디스크에 먼저 기록하고 비동기로 S3에 동기화합니다(NVMe끼리 복제할 수도 있고, 장애 복구만 해도 됩니다). 이전에는 원격 NVMe 디스크를 쓰기 통과(write-through) 캐시로 썼지만, Git에서는 S3 지연 시간이 너무 길어서 통하지 않았습니다.

  17. EngineeringStuf HN

    저희도 Swarmfile에서 비슷한 것을 만들었고, Git과도 호환됩니다.

  18. fischeti HN

    덧붙이면 좋을 점은, 그 250개 파일은 내용이 같아서 해시도 같기 때문에 하나의 blob 객체로 저장된다는 겁니다. 그러니 이 예시에서는 저장 공간이 상당히 재사용되는 셈입니다.

  19. lucasoshiro HN

    최신 버전 Git에서는 새 명령 git repo structure[1]로 이걸 확인할 수 있습니다.

    [1] https://git-scm.com/docs/git-repo#Documentation/git-repo.txt-structure--formattablelinesnul-z

  20. CodesInChaos HN

    Git은 deflate보다 나은 압축 알고리즘, 예컨대 zstd나 brotli를 지원하나요?

  21. masklinn HN

    아니요. 압축 수준은 설정할 수 있지만 거기까지입니다.

    느슨한 객체(loose object)와 팩 압축은 따로 설정할 수 있으니(core.compression과 pack.compression), 느슨한 객체 압축은 완전히 로컬 문제라 다른 알고리즘(압축률이 낮은 zstd 정도)으로 바꿀 수도 있습니다[1]. 하지만 팩 파일은 네트워크 교환에 쓰이기 때문에 그쪽은 좀 더 복잡합니다. 또 짜증 나는 점은 Git이 헤더나 식별자 없이 날것의 zlib을 쓴다는 것입니다.

    메일링 리스트에 오래된 스레드가 있고 gitlab 이슈도 있습니다.

    그래도 팩을 명시적으로 만들 때 팩마다 압축을 조정할 수는 있습니다. 저는 회사 저장소에서 gc 속도를 높이려고, 이미지를 압축하지 않은 채 별도 팩에 모아 두는 .keep 팩을 둡니다. jpeg나 png를 zlib으로 압축하느라 사이클을 낭비할 이유가 없으니까요.

    [1]: "dumb http" 프로토콜을 쓰거나 (n)fs를 통한 클론을 하는 경우는 제외입니다.

  22. CodesInChaos HN

    GitHub나 다른 대형 Git 호스팅 업체가 이런 프로토콜 개선을 밀어붙이지 않은 게 조금 놀랍습니다. 팩이 더 작고 만드는 비용도 싸지면 비용이 눈에 띄게 줄 것 같은데요.

  23. masklinn HN

    팩 안의 객체는 개별적으로 압축됩니다. 압축의 비용과 이득은 보통 델타화(delta-ification)에 비하면 미미하리라 생각합니다.

  24. 112233 HN

    제 로컬 실험에서는 제가 생각해 낸 어떤 기발한 방식도 단순한 대형 윈도 zstd를 이기지 못했습니다. 속도도, 결과 크기도 그랬습니다(윈도에 필요한 메모리는 완전히 별개의 문제지만요). zstd는 Git의 xdelta+deflate도 이겼습니다.

    사실 가장 공짜 점심에 가까운 것은 fast export(또는 비슷한 형식)를 압축하는 겁니다. 저장소를 최대한 작게 묶는 게 목표라면, 커밋과 트리 객체의 모든 SHA는 다른 데이터에서 파생된 압축 불가능한 데이터이고, fast export처럼 단순한 참조를 쓰면 아카이브 크기가 절반으로 줄 수도 있습니다.

  25. fiddlerwoaroof HN

    느슨한 객체가 팩 파일로 묶이면 델타 압축 덕분에 훨씬 더 작아질 수 있습니다. 똑같은 파일 여러 개를 사본 하나를 저장하는 정도의 최소한의 오버헤드로 저장할 수 있으니까요.

  26. gblargg HN

    맞습니다, 장기적으로 중요한 것은 정말 팩 파일 크기입니다. 단기적으로는 파일을 아주 조금만 바꿔도 전체가 (압축된 채로) 다시 추가되지만, 팩 파일에서는 아주 조금 바뀐 것이 거의 아무것도 추가하지 않아야 합니다. 디스크 공간이 아주 부족한 경우가 아니라면, 크기로서 의미가 있는 것은 장기적인 크기뿐입니다.

  27. masklinn HN

    팩 파일에서는 아주 조금 바뀐 것이 거의 아무것도 추가하지 않아야 합니다

    글쎄요, Git이 적절한 델타를 찾아낼 수 있는 한에서는 그렇죠. 그게 어려운 부분이고요.

  28. bewuethr HN

    "foo"만 들어 있는 그 250개 파일도 팩 파일을 만들기 전부터 이미 하나의 blob으로 저장될 거라고 생각합니다.

  29. fiddlerwoaroof HN

    그건 잊고 있었네요. 거의 똑같은 파일이 있을 때는 델타 압축이 여전히 꽤 많이 절약해 줍니다.

  30. bewuethr HN

    맞아요, 큰 파일을 조금만 바꿔도 완전히 새 blob이 생기지만, 팩 파일에서는 델타로 아주 효율적으로 저장됩니다.

Hacker News에서 보기 ↗