Ref, HEAD, index가 object를 일상 명령과 이어
Object가 내용이라면 ref는 이름이야. Commit에 main이나 v2.4.0처럼 사람이 읽는 이름이 붙는 까닭은 .git/ 아래 refs/ 계층의 작은 hash 파일과 오래된 entry를 모은 packed-refs 덕분이야. HEAD는 ref를 가리키거나 detached 상태에서는 commit을 직접 가리키는 특별한 pointer야. ref, HEAD, index가 object database와 일상 명령 사이의 다리가 돼.
Ref는 세 하위 tree에 살아. refs/heads/<name>은 로컬 branch, refs/remotes/<remote>/<branch>는 마지막 fetch 때 본 remote의 읽기 전용 그림자인 remote-tracking branch, refs/tags/<name>은 tag야. Lightweight tag는 hash를 직접 가리키고 annotated tag는 tag object를 가리켜. git for-each-ref로 모두 살펴볼 수 있어.
HEAD는 Git이 모든 연산에서 수정하는 유일한 pointer야. 보통 내용은 ref: refs/heads/main처럼 branch를 가리키는 symbolic ref지. commit하면 Git이 commit object와 branch ref를 새 commit으로 갱신하고 HEAD는 같은 branch를 가리킨 채 새 tip에 있게 돼. branch를 switch하면 HEAD의 symbolic ref가 바뀌고 특정 commit을 checkout하면 HEAD가 hash를 직접 담아 detached HEAD가 돼.
세 번째 구조인 index는 .git/index의 binary file로 다음 commit의 tree 모양을 묘사해. 추적하는 path와 mode, blob hash, timestamp, 진행 중 merge의 stage 정보가 들어 있어. git ls-files --stage로 읽을 수 있어. git diff는 작업 트리와 index를, git diff --staged는 index와 HEAD tree를 비교해. Index가 있기 때문에 git add로 commit할 조각을 고를 수 있어.