Git HEAD와 브랜치의 관계

Git을 처음 쓸 때 제일 헷갈렸던 게 HEAD였다. 브랜치가 뭔지도 모르는데 HEAD가 무슨 뜻인지 몰랐다.

HEAD의 정체

HEAD는 현재 작업 중인 위치를 가리키는 포인터다. .git/HEAD 파일에 저장되어 있다.

HEAD는 보통 브랜치를 가리키고, 브랜치는 커밋을 가리킨다:

HEAD → main → commit_abc

브랜치를 만들면 어떻게 되나

git branch highlevel로 새 브랜치를 만들면:

HEAD → main → commit_abc
              commit_abc ← highlevel

두 브랜치가 같은 커밋을 가리킨다. git checkout highlevel을 하면:

HEAD → highlevel → commit_abc

이제 커밋을 두 번 하면:

main      → commit_abc
highlevel → commit_abc → commit_def → commit_ghi (HEAD 위치)

히스토리가 두 갈래로 나뉜다.

merge

git checkout maingit merge highlevel을 실행하면:

main → commit_abc → merge_commit (HEAD)
                  ↗
highlevel → commit_ghi

merge commit은 두 부모 커밋을 모두 가리키는 특수한 커밋이다.

Detached HEAD

git switch [커밋해시] --detach로 특정 커밋 시점으로 이동하면 Detached HEAD 상태가 된다.

git status 실행 시:
HEAD detached at b0442df (빨간 글씨)

이때 HEAD는 브랜치를 거치지 않고 커밋을 직접 가리킨다:

HEAD → commit_b0442df (브랜치 없음)

이 상태에서 커밋하면 어느 브랜치에도 속하지 않는 orphan commit이 생긴다. 나중에 브랜치를 전환하면 이 커밋은 참조가 없어서 사라질 수 있다.

이 커밋을 유지하려면:

git branch -f main HEAD    # main 브랜치를 현재 HEAD로 강제 이동
git checkout main          # main으로 전환

정리

  • 브랜치: 특정 커밋을 가리키는 라벨. 새 커밋이 생기면 자동으로 따라간다.
  • HEAD: 현재 내가 어디서 작업하는지. 보통 브랜치를 통해 간접적으로 커밋을 가리킨다.
  • Detached HEAD: HEAD가 브랜치 없이 커밋을 직접 가리키는 상태.