2023. 4. 23. 18:14ㆍGit
1. Git의 HEAD의 개념
2. 상대 참조
Git을 사용하다 보면 HEAD라는 단어를 보게 된다.
다만 지금 처리해야 하는 업무에는 상관없으니까 담에 알아봐야지 하고 넘어가기 일쑤다.
이번 포스팅을 통해 Git에서 HEAD가 어떤 개념을 가지고 있고, 어떻게 사용할 수 있는지 알아보자.
HEAD란 ?
HEAD 는 포인터이다.
바로 현재 체크아웃 되어있는 Branch의 마지막 Commit을 가리키는 포인터다.
Branch를 통해 간접적 가리키거나, Commit을 직접 가리킬 수도 있다.
git clone [url]
git log
프로젝트를 clone 받았을 때 git log 명령어를 실행해보면 다음과 같다.
HEAD -> main를 볼 수 있는데,
현재 HEAD가 main branch를 가리키고 있다는 것이다.
이는 main branch를 통해 특정 Commit을 간접적으로 가리키고 있는 것이다.
HEAD와 main branch를 분리하여 HEAD가 직접 Commit을 가리킬 수도 있다.
git checkout 51b9998d8aaede7255b266603db0fc7433c51f68
Image 1에서의 main branch가 가리키고 있던 commit (id: 51b9998d8aaede7255b266603db0fc7433c51f68 이하 “51b9998d”)으로 checkout 했더니 HEAD -> main 이 HEAD, main으로 분리되었다.
아래 이미지처럼 표현할 수 있다.
사실 commit id 전체를 입력할 필요는 없다.
식별될 수 있는 정도까지만 입력해도 Git은 처리해준다.
“git checkout 51b9998d” << 이렇게만 입력해도 된다
Git은 왜 포인터라는 개념을 사용할까 ?
Git은 해당 Branch의 마지막 Commit 정보를 기반으로 새로운 Commit을 생성한다.
Image 4에서도 볼 수 있듯이 M1 Commit을 기반으로 M2를, M2 Commit을 기반으로 M3를 생성한다.
이때 포인터를 사용하면 효율적이다.
매번 commit 할 때마다 해당 Branch의 마지막 Commit 정보를 찾는것이 아니라
포인터를 통해 빠르게 스냅샷을 쉽게 생성할 수 있다.
정리하면,
HEAD는 현재 checkout 되어있는 Branch의 마지막 Commit을 가리키는 포인터다.
Git이 새로운 Commit을 생성할 때 HEAD를 참조함으로써 효율적으로 작동하도록 도와준다.
몇 가지를 확인해보자
Case 1. main branch의 중간의 commit으로 checkout 한 후 commit
git checkout 899f0b4331f6a156d715b82cf0bd51e6588047e6
git log --all
위 이미지(Image 5)는 899f0b4331f6a156d715b82cf0bd51e6588047e6(이하 “899f0b43”) Commit으로 checkout 한 상태이다. 이 상태에서 git log 명령어를 실행해보면 아래와 같다.
위 이미지(Image 6)를 보면 HEAD가 현재 Brach의 마지막 Commit을 가리키고 있다.
각 Commit은 부모를 참조하고 있지만 자식은 참조하고 있지 않기 때문에
특정 Commit으로 checkout 했을때, 해당 Commit의 입장에서는 Branch의 마지막 Commit인 셈이다.
이제, 파일을 수정하고 commit을 해보자.
HEAD가 가리키고 있던 899f0b43 Commit에서 새로운 Branch가 뻗어 나와 Commit이 생성되었다. 이처럼 Git은 HEAD가 가리키는 Commit을 기반으로 새로운 Commit을 생성한다.
“ HEAD는 현재 checkout 되어있는 Branch의 마지막 Commit을 가리키는 포인터다. Git이 새로운 Commit을 생성할 때 HEAD를 참조함으로써 효율적으로 작동하도록 도와준다.”
2. 새로운 Branch를 만들고 commit
git branch git-head-example
git log --all
위 이미지(Image 9)는 51b9998d8 Commit에서 git-head-example Branch를 생성했다. 이후 파일을 수정한 후 commit을 해보면 다음과 같다.
의도는 방금 만든 git-head-example Branch에 commit 되어 새로운 줄기가 뻗어 나오는 모양이 되는 것이었다.
하지만 git-head-example이 아닌 main Branch에 Commit이 생성되었다.
범인(?)은 바로 HEAD다.
Image 9의 HEAD -> main을 보면 현재 HEAD는 main Branch의 마지막 Commit을 가리키고 있다.
“ HEAD는 현재 checkout 되어있는 Branch의 마지막 Commit을 가리키는 포인터다.
Git이 새로운 Commit을 생성할 때 HEAD를 참조함으로써 효율적으로 작동하도록 도와준다.”
따라서 의도대로 git-head-example Branch에 이어 붙이기 위해서는 HEAD를 옮겨주어야 한다.
git checkout git-head-example
위 명령어로 git-head-example Branch의 마지막 Commit으로 이동하자.
이제 파일을 수정하고 commit 하면 의도한 대로 동작한다.
Case 2을 정리해보면 아래 이미지와 같다.
상대 참조
git checkout [commit id] / [branch 명]
Git의 작업 트리를 이동(HEAD를 변경)하기 위해서는 위 명령어를 사용하면 된다.
여기서 commit id로 checkout을 할 때는 해시값을 넣어야 하는데 여간 귀찮은게 아니다.
위에서 설명할 때 봤던 해시값도 899f0b4331f6a156d715b82cf0bd51e6588047e6 처럼 지독하게 길다.
물론 899f 만 입력해도 값이 고유하다면 가능하다.
이때, Git의 상대 참조(Relative Ref)를 사용하면 굉장히 편리하다.
상대 참조로 특정 Commit을 기준으로 다른 지점에 checkout 할 수 있다.
- ^ : 한 커밋 위로 이동
- ~<num> : num 만큼의 Commit 위로 이동
git checkout main^
or
git checkout HEAD^
git checkout main~2
or
git checkout HEAD~2
마무리
Part 2에서는 HEAD를 알아봤다.
또, 상대 참조를 통하여 보다 쉽게 Commit을 옮겨 다닐 방법을 소개했다.
Part 3에서는 작업 트리를 수정하는 방법에 대해서 소개하려고 한다.
** 사실과 다른 게 있다면 언제든지 조언 부탁드립니다.
'Git' 카테고리의 다른 글
[Git] 깃 실속있게 정복하기 Part 3 (0) | 2023.04.23 |
---|---|
[Git] 깃 실속있게 정복하기 Part 1 (0) | 2023.04.23 |