Patch 가 아니라 snapshot
Git 에 대한 가장 흔한 오해는 'diff 를 저장한다' 는 거야. version N → N+1 의 차이만 보관한다고 생각하는데, 그건 SVN, CVS 모델이지. Git 은 본질적으로 달라. 모든 commit 은 모든 파일의 완전한 snapshot 이고, hash 로 주소지정돼.
두 commit 사이에 파일이 안 바뀌었으면 Git 은 두 번 저장 안 해. 같은 blob 을 가리키는 pointer 만 둬. 같은 내용은 항상 같은 hash 라서 dedup 이 자동이고, 1 bit 만 바뀌어도 완전히 다른 hash 라서 corruption 탐지가 돼. Git 의 history 연산이 빠른 이유가 이거야 — 어떤 version 보여줄 때 해당 snapshot 만 load 하면 되거든. 프로젝트 시작부터 diff 다 replay 할 필요가 없어.
세 가지 object type 으로 이걸 굴려. blob 은 파일 하나의 raw bytes. tree 는 directory listing — 이름/mode/그게 가리키는 blob hash. commit 은 tree hash + parent hash + author + committer + message 가 든 작은 object. 다 .git/objects/ 에 자기 SHA-1 이름으로 살아. branch 는 commit 하나 가리키는 41 byte. tag 는 아무 object 가리키는 41 byte. graph 전체가 content-addressable 이야.
git cat-file 매일 칠 일은 없어. 그래도 blob 하나, tree 하나, commit 하나 손으로 펼쳐보는 건 diff-기반 mental model 에 대한 백신이야. 한 번 보고 나면 branch 가 신비롭지 않고 merge 가 무섭지 않아져.