Git detached HEAD에서 빠져나오기 — 원인과 커밋 복구
과거 커밋을 확인하려고 커밋 해시를 체크아웃했더니 낯선 경고가 길게 출력됩니다.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.경고의 길이 때문에 큰 사고처럼 보이지만, 결론부터 정리하겠습니다. detached HEAD는 고장이 아니라, HEAD가 브랜치가 아닌 커밋을 직접 가리키고 있는 상태입니다. 상태 자체는 아무것도 망가뜨리지 않습니다. 다만 이 상태에서 커밋을 만들고 아무 조치 없이 떠나면 그 커밋을 잃을 수 있으므로, 구조와 탈출법을 알아 두어야 합니다.
HEAD가 분리된다는 것의 의미 #
평소의 HEAD는 커밋이 아니라 브랜치를 가리킵니다. main 위에서 커밋을 만들면 main 포인터가 새 커밋으로 전진하고, HEAD는 main을 따라 자동으로 함께 움직입니다.
그런데 브랜치가 아니라 특정 커밋의 해시나 태그를 직접 체크아웃하면, HEAD가 브랜치를 거치지 않고 그 커밋을 곧바로 가리키게 됩니다. 브랜치에서 떨어져 나왔다는 의미로 detached, 즉 분리된 HEAD라고 부릅니다.
[정상 — attached]
HEAD ──▶ main ──▶ C3
[분리 — detached]
HEAD ──────────▶ C1 (브랜치를 거치지 않음)detached 상태로 들어가는 경로는 대체로 세 가지입니다.
- 과거 커밋이나 태그를 직접 체크아웃 —
git checkout 1a2b3c4,git checkout v2.1.0, 또는 명시적으로git switch --detach 1a2b3c4 - bisect 진행 중 — 이진 탐색이 중간 커밋을 하나씩 체크아웃하므로 탐색 내내 detached 상태입니다.
git bisect reset으로 끝내면 원래대로 돌아옵니다. - 서브모듈 내부 — 서브모듈은 특정 커밋으로 고정해 참조하는 구조라, 그 디렉터리 안은 기본적으로 detached 상태입니다.
무엇이 문제인가 — 어느 브랜치에도 속하지 않는 커밋 #
detached 상태에서 코드를 보기만 한다면 아무 위험이 없습니다. 문제는 커밋을 만들었을 때입니다.
브랜치 위에서 만든 커밋은 브랜치 포인터가 참조를 유지해 줍니다. 그런데 detached 상태에서 만든 커밋은 어떤 브랜치도 가리키지 않습니다. 이 상태에서 git switch main으로 떠나는 순간, 방금 만든 커밋들은 도달할 수 없는 상태가 되고, 시간이 지나면 가비지 컬렉션의 정리 대상이 됩니다. Git도 이를 알기 때문에 떠나는 시점에 마지막 경고를 출력합니다.
Warning: you are leaving 2 commits behind, not connected to
any of your branches:
8f3c2d1 실험: 캐시 크기 조정
5e9a7b4 실험: 캐시 통계 출력
If you want to keep them by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 8f3c2d1경고가 해법까지 알려 줍니다. 커밋에 브랜치를 걸어 주면 됩니다.
상황별 탈출법 #
detached HEAD에서 빠져나오는 방법은 지금까지 무엇을 했는지에 따라 세 가지로 갈립니다.
구경만 했다면 — 그냥 돌아갑니다.
git switch --는 직전에 있던 브랜치를 뜻합니다. 커밋을 만들지 않았다면 이 한 줄로 상황이 끝납니다.
커밋을 만들었고 남기고 싶다면 — 브랜치를 걸고 나갑니다.
git switch -c experiment-cache지금 HEAD가 가리키는 커밋 위에 새 브랜치가 생기면서 HEAD도 그 브랜치에 다시 연결됩니다. 커밋들은 이제 브랜치가 참조하고 있으므로 잃을 걱정이 없습니다.
이미 떠나서 커밋을 잃었다면 — 해시를 찾아 브랜치를 겁니다.
떠날 때 출력된 경고에 커밋 해시가 찍혀 있으므로, 그 해시로 브랜치를 만들면 됩니다.
git branch experiment-cache 8f3c2d1터미널을 닫아 경고를 잃어버렸다면 reflog에서 찾습니다. detached 상태에서 만든 커밋도 reflog에는 전부 기록되어 있습니다. 해시를 찾는 절차는 지운 Git 커밋과 브랜치 살리기 — reflog 복구 절차에서 정리했습니다.
git switch <브랜치>로 브랜치에 연결한 뒤 커밋해야 합니다.애초에 안전하게 구경하는 습관 #
과거 시점의 코드를 확인할 일이 있다면, 들어가기 전에 브랜치를 만들어 두는 편이 깔끔합니다.
git switch -c temp-look 1a2b3c4
# 확인이 끝나면
git switch main
git branch -d temp-lookdetached 상태 자체를 만들지 않으므로 경고도 커밋 유실 가능성도 없습니다. 확인만 하고 커밋하지 않았다면 브랜치 삭제로 흔적 없이 정리됩니다.
마무리 #
이번 글의 핵심은 세 가지입니다.
- detached HEAD는 HEAD가 브랜치 대신 커밋을 직접 가리키는 상태이고, 그 자체로는 아무것도 망가뜨리지 않습니다.
- 위험은 이 상태에서 만든 커밋에만 있습니다. 떠나기 전에
git switch -c <브랜치>로 브랜치를 걸면 안전하고, 이미 떠났다면 경고의 해시나 reflog로 복구합니다. - 과거 시점을 확인할 때 처음부터 임시 브랜치를 만들어 들어가면 이 상태를 아예 만나지 않습니다.
경고 메시지가 길어서 위협적으로 읽히지만, 내용은 안내에 가깝습니다. 구조를 한 번 이해해 두면 detached HEAD는 사고가 아니라 Git이 제공하는 자유로운 탐색 모드로 쓸 수 있습니다.