Patch가 아니라 스냅샷
Git을 “diff를 차곡차곡 저장하는 도구”로 이해하기 쉬워. 버전 N에서 N+1로 바뀐 부분만 보관한다고 생각하는 거지. SVN이나 CVS는 그 그림에 가깝지만 Git은 달라. Commit 하나는 그 시점의 프로젝트 전체 스냅샷이고, 내용에서 계산한 hash로 찾아가.
그렇다고 안 바뀐 파일을 commit마다 또 저장하진 않아. 이전과 같은 파일은 같은 blob을 가리켜. 내용이 같으면 hash도 같으니 중복은 자연스럽게 합쳐지고, 1 bit만 달라져도 hash가 바뀌어서 손상도 알아챌 수 있어. 특정 시점을 보여줄 때는 그 스냅샷을 바로 읽으면 돼. 처음부터 diff를 전부 재생할 필요가 없어서 이력 탐색도 빨라.
이 구조의 중심에는 세 object가 있어. blob은 파일 하나의 raw bytes, tree는 이름과 mode, blob hash를 묶은 디렉터리 목록, commit은 tree hash와 parent hash, author, committer, message를 담은 작은 object야. 모두 .git/objects/ 아래에 자기 SHA-1 이름으로 살아. Branch는 commit 하나를 가리키는 41 byte짜리 이름표고, tag는 object 하나를 가리키는 41 byte짜리 이름표야. 그래프 전체가 내용으로 주소를 찾는 구조지.
git cat-file을 매일 쓸 필요는 없어. 그래도 blob, tree, commit을 한 번씩 직접 펼쳐보면 “Git은 diff 묶음”이라는 오해가 확실히 사라져. 그러면 branch는 가벼운 이름표로, merge는 그래프를 잇는 동작으로 보이기 시작해.