Back

Git은 내부적으로 어떻게 작동할까? 객체, 트리, 그리고 블롭

우리는 매일 git add, git commit, git push를 사용합니다. 하지만 .git 폴더 내부를 들여다본 적이 있나요?

Git의 내부를 이해하면 "마법"이 풀리고, 훨씬 더 자신감 있는 사용자(그리고 병합 충돌 해결사!)가 될 수 있습니다.

본질적으로 Git은 **콘텐츠 주소 지정 파일 시스템(Content-addressable filesystem)**입니다. 쉽게 말해 키-값 저장소입니다:

  • Key: 콘텐츠의 SHA-1 해시.
  • Value: 콘텐츠 그 자체.

Git이 기록을 저장하는 데 사용하는 세 가지 주요 객체를 살펴보겠습니다.

1. 블롭 (Blob - Binary Large Object)

파일을 git add하면, Git은 해당 파일의 내용을 가져와 Blob으로 저장합니다.

  • 파일 이름은 저장하지 않고, 오직 내용만 저장합니다.
  • 두 파일의 내용이 완전히 같다면, 같은 Blob을 공유합니다 (중복 제거!).

git cat-file 명령어로 확인할 수 있습니다:

$ echo "hello" | git hash-object -w --stdin ce013625030ba8dba906f756967f9e9ca394464a

저 해시값이 키가 됩니다.

2. 트리 (Tree)

그렇다면 파일 이름은 어디에 저장될까요? 바로 Tree 객체입니다.

Tree는 디렉토리와 같습니다. 다음 정보들의 목록을 담고 있습니다:

  • 파일 권한 (예: 100644)
  • 객체 타입 (blob 또는 tree)
  • SHA-1 해시
  • 파일 이름

Tree를 폴더 구조의 스냅샷이라고 생각하면 됩니다.

100644 blob ce0136...    hello.txt
100644 blob 9a8b7c...    README.md
040000 tree 3b1c2d...    src

3. 커밋 (Commit)

마지막으로 Commit 객체가 있습니다.

커밋은 단순히 특정 Tree(그 시점의 프로젝트 스냅샷)를 가리키고 메타데이터를 추가하는 래퍼(wrapper)입니다:

  • 작성자(Author) & 커미터(Committer)
  • 날짜
  • 커밋 메시지
  • 부모 커밋 해시 (Parent Commit hash)

각 커밋이 부모를 가리키기 때문에, 이들은 연결 리스트(정확히는 방향성 비순환 그래프 - DAG)를 형성합니다.

tree 3b1c2d...
parent 8a9b0c...
author John Doe <[email protected]>
committer John Doe <[email protected]>

Initial commit

객체 간의 관계 시각화

graph TD subgraph Commit C[Commit Object] -->|Points to| T[Tree Object] C -->|Points to| P[Parent Commit] end subgraph Tree T -->|Contains| B1[Blob: hello.txt] T -->|Contains| B2[Blob: README.md] T -->|Contains| T2[Tree: src] end subgraph Blob B1 -->|Content| Content1["hello"] B2 -->|Content| Content2["# Readme"] end

종합해보면

git commit을 실행할 때 일어나는 일:

  1. Git은 변경된 파일들에 대해 Blob을 생성합니다.
  2. Git은 프로젝트 구조를 나타내는 Tree를 생성합니다.
  3. Git은 그 Tree와 이전 커밋을 가리키는 Commit 객체를 생성합니다.
  4. 브랜치 포인터(예: main)가 이 새로운 커밋 해시로 이동합니다.

이것이 왜 중요할까요?

  • Git은 불변(Immutable)입니다: 객체가 한 번 생성되면 절대 변경되지 않습니다. 기록을 "수정"하는 것은 사실 새로운 객체를 만드는 것입니다.
  • 저렴한 브랜치: 브랜치는 커밋 해시 하나를 담고 있는 40바이트짜리 아주 작은 파일일 뿐입니다. 브랜치 생성에는 비용이 거의 들지 않습니다.
  • 무결성: SHA-1 해시 덕분에 데이터가 1비트만 바뀌어도 ID가 바뀝니다. 감지되지 않고 기록을 훼손하는 것은 불가능합니다.

다음에 "detached HEAD" 상태에 빠지게 된다면 기억하세요: 당신은 단지 브랜치 이름표가 붙지 않은 커밋 객체를 가리키고 있을 뿐입니다!

TechGitVCSInternals

관련 도구 둘러보기

Pockit의 무료 개발자 도구를 사용해 보세요