깃으로 버전관리 하다보면 작업내용을 commit하고 원격저장소에 push할 때, detached head 상태에 있다며, push가 reject될 때가 있다.
빨리 저장소에 push해야하는 상황에서 이런 오류를 마주치면 당황하기 쉽상이다. 이미 commit은 했는데 push는 reject당했고, ide에 git graph를 보면 내가 방금 한 커밋은 보이지도 않고.. 처음 겪으면 눈 앞이 캄캄해진다.
간단한 해결법으로는 아래 명령어로 새 branch를 하나 파면서 checkout하고, 다시 원래 작업하던 branch로 checkout 하면 끝이다.
$ git checkout -b <branch>
하지만 detached head가 정확히 뭔지, 왜 detached head 상태가 되는지 이해가 부족해서 알아봤다.
Detached Head란, 말 그대로 head가 (branch로부터) 떨어져있는 상태를 뜻한다.
즉, branch를 통해서가 아니라 직접 다이렉트로 commit을 참조하고 있는 상태를 뜻한다.
git 에서 head는 단 하나만 존재한다. 시작점 같은 개념이다. 일반적으로 git에서 head는 특정 branch를 가리키고 branch는 다시 특정 commit을 가르킨다. 보통의 경우엔 head-> branch -> commit 의 참조순서를 가진다.
하지만 이 때, check out 명령어로 특정 커밋으로 check out할 경우, 깃은 참조하던 branch를 잃어버리고, 직접 특정 commit을 참조하는 detached head 상태가 된다.
git checkout <revision number> 명령어를 사용해, 특정 커밋으로 check out할 경우 detached head 상태가 된다.
내 생각엔, cli환경에서 직접 check out 하는 것이 아닌 inteliJ같은 ide 또는 git gui 툴을 쓰면서 과거에 커밋한 내용들을 찾아보려다가 커밋 이력을 더블클릭해버려서 나도 모르게 해당 커밋으로 check out 되고, 자신이 현재 detached head 상태인지 모른 채로 작업 후 commit & push하려다가 reject되는 상황에 처하는 경우가 많은 것 같다.
돌이켜보니 나의 경우도 그랬다.
phpstorm에서 git graph를 간략하게 볼 수 있는데 여기서 커밋 메세지를 더블클릭하면 check out이 돼버린다!
stackoverflow에 마침 이 detached head에 대해 자세히 설명한 답변글이 있어서 한 번 살펴보겠다.
1.현재, head는 master를 통해서 69084f3라는 revision number를 가진 commit을 참조하고 있다.
이 커밋은 22d1c79라는 커밋 이후에 두 번째로 한 커밋이다. ↓↓↓↓
2. 그런데, 어떤 이유로 나도 모르게(주로, 위에서 언급한 gui환경에서의 부주의 때문에) 첫번째 커밋으로 체크아웃해서 detached head 상태가 되었다. ↓↓↓↓
3. 여기서 head -> branch -> commit의 참조순서를 제대로 모르는 상태에서, 다시 이전으로 원상복구 한답시고 두 번째 커밋인 69084f3으로 check out했다. ↓↓↓↓
4.
상황1. 뭐가 잘못된 것 같은데, 무슨 문제인지 몰라서 소스코드에 띄어쓰기 한칸 더 넣고 새로 커밋을 한다. 하지만 ide 내장 git graph에서는 내가 방금 한 새 커밋은 온데간데 보이지도 않는다. 실제 상황은 아래 그림과 같이, detached head는 세 번째 커밋인 783fbf2를 참조하고, master 브랜치는 여전히 두 번째 커밋을 참조하고 있다.
상황2. 3번에서 문제가 해결된 줄 알고 열심히 작업해서 세 번째 커밋을 하고 push하려니 reject 당했다. 뭐가 문제인지 파악하려고 git graph를 보니 내가 방금 한 커밋이 보이지 않는다.
5. 4에서 상황 1의 경우, 세 번째 커밋은 별 필요가 없으므로 아래의 명령어를 쳐서, head가 master branch를 참조하게끔 하면 문제가 해결된다.
git checkout master
6. 4에서 상황 2의 경우, 세 번째 커밋을 유지하려면 아래의 명령어로, master branch를 세번째 커밋을 참조하게끔 만들고,
git branch -f master HEAD
이어서 head가 master branch를 참조하게끔 branch로 checkout해주면 된다.
git checkout master
매우 친절한 답변 뒤에 뼈때리는 진심어린 충고의 멘트가 너무도 와닿는다.
Learning Git in an IDE is a recipe for disaster.
gui환경에서 git을 사용하더라도, 반드시 cli에서 git을 자유롭게 쓸 수 있는 정도까지 git을 익힌다음 사용하도록 하자!
참조 : https://stackoverflow.com/questions/34987957/how-did-i-end-up-with-a-detached-head