꺼내먹는지식 준

GITHUB 협업5 중급자 코스 Head, Master, Amend, Checkout, Reset 본문

CS/깃헙

GITHUB 협업5 중급자 코스 Head, Master, Amend, Checkout, Reset

알 수 없는 사용자 2022. 5. 9. 15:07

해당 글은 본 블로그의 github 글을 따라 읽어온 사람들만 이해할 수 있다. 

Head, Master, Checkout, Reset, Ammend 에 대한 빠른 이해를 위해 글을 선택한 사람들은 다른 블로그의 글을 참고하는 것을 추천 

본 글을 이해하고, 다음글에서는 최종장인 Rebase 에 대해 이해한다. 


Recall 

다음의 3가지 기능을 한번 복기하고 시작하자. 

 

Master 

: 마스터는 브랜치의 마지막 작업 버전을 가리킨다. 

 

Head 

: 해드는 현재 working directory를 가리킨다. 

 

Head랑 Master는 어떻게 다른가? 마지막 작업 버전과 현재 working directory 가 다를 수가 있나? 

우선적으로 Master 는 사실 그냥 branch 중 하나일 뿐이다. repository를 생성할 때 처음 생성되는 branch이다. 

중요한 건 Head 이다. Head 는 항상 현재 directory를 가리킨다. 

 

commit id 

Git은 버전 아이디를 만들 때, 내용 작성자, 작성자의 이메일, 커밋 메시지, 시간 등을 합쳐서 hash 값을 만들어 고유한 식별자를 만든다. 이로 인해 아이디가 곂치는 경우는 없다고 생각하면 된다. 

 

Checkout 

: Head 이동 

 

자세한 건 해당 글 참고


※.gitignore

종종 repository에 보면 .gitignore 파일이 있는 것을 본다. local에서 작업을 해도 remote repository에 파일을 올리고 싶지 않은 경우가 있다. 이럴 때 .gitignore 에 파일명을 기입하면 git status 로 상태를 추적해도 추적되지 않고 무시된다. 

 

Amend 

Amend는 주로 commit 을 수정할 때 사용한다. 동작 원리를 살펴보면  전 커밋 자체를 삭제하는건 아니다. 그도 그럴게, 그냥 삭제해 버리면 amend 를 실수로 잘 못 한 경우 되돌리는 것이 불가능하다. 

이로인해, amend 는 바로 위 그림처럼 동작한다. A < B 에 C commit을 수행하였다가 (내용 추가 등의 이유로)수정하기 위하여

git commit --amend -m "c2"

를 처리하면 기존의 master branch는 c2를 가리키게 되고, c2는 기존의 commit B를 가리킨다. 이로인해 commit c 와 연결이 끊기게 된다. 

이때 만약 amend 를 취소하고 싶으면 어떻게 하야 할까? 

master 를 어떻게 해서든 다시 c로 보내면 된다. 

이를 이해하기 위해서는 reset 에 대한 선 이해가 필요하다. 


많이 혼동하는 Revert, Checkout 과 비교하며 설명한다. 

Reset vs Revert 

Reset vs Checkout 

 

먼저 가장 간단한 checkout에 대해 설명해본다. 

 

git check out 은 말그대로 Head 의 위치만 변경한다. "마지막 커밋인 B를 가리키는 master" 를 가리키는 Head 의 위치가 checkout A commit id 로 인해 이동된 것이 아래의 그림이다. 

이때 다시 원상복귀 하려면 git checkout master 를 통해 master 를 가리키면 된다. 

 

사실 이건 약간 위험한 상태이다. 

깃헙 협업 첫번째 글에서 언급했지만, commit은 Head 가 가리키는 곳을 parent로 한다. 

그로인해 master와 Head 가 detach된 상태에서 commit을 하면 새로운 commit E는 D를 참고하고, master가 last commit이 아닌, Head 가 last commit이 된다. 

여기서 다시 maser로 checkout을 하면 E 를 그대로 날리게 된다! 이때는 약도 없다. 

 

하지만, reset은 Head 가 가리키는 branch 자체를 움직인다! 

이게 무슨 말인고 하면 

git reset —hard 4f46

다음과 같이 commit id 4f46으로 이동을 하면, master를 두고 Head 만 움직이는 것이 아니라 그냥 branch 자체가 이동이 된다! 

엄청나게 편리하고 직관적 기능이다. 

마치 삭제해버리는 것과 같은데, 왜 이름을 Delete 라고 사용하지 않고 reset으로 했을까? 

이는 Reset이라는 기능 자체에 주목을 해야한다. 

Reset은 비단 삭제 뿐만 아니라 동시에 복원을 할때도 사용이 된다. 

다음의 사진을 살펴보자. 실수로 A로 reset하여 B를 지워버렸다. 어떡하면 좋을까.. 

이때 Git reset "commit id" 로 복원이 가능하다! 

 

근데, 누가 commit id 를 적어놓을까? 이미 사라져서 commit id 는 볼 수가 없다. 

 

흑흑 좀 적어놓을걸.. 이라고 생각도 잠시 

git reflog 라는 기능을 알면 걱정 없다. 

 

git reflog 

왼쪽은 결과 commit id, 오른쪽은 원인이다. 

 

또 좋은 기능이, 해당 git reflog에서 보이는 commit id가 아니라 단순히 HEAD@{N} 을 대신 사용해도 된다. 

즉, 

git reset HEAD@{1}

이런식으로 사용이 가능하다. 

 

개인적으로는 reset, checkout만 알아도 git 협업에 문제는 없다고 생각한다. 


정리하자

Head: 현재 working directory 

master: branch에서 마지막 작업한 버전 

Checkout: Head 움직이기 

reset: branch 움직이기 

 

하지만 아직 언급 안한 것이 있는데, 바로 상황에 따른 reset의 기능 변화이다. 

 

전 예시에서 reset을 사용할 때는 master를 Head 가 가리키고 있는 상황이었기에 branch를 이동시킬 수 있었지만, 만약 master와 Head 가 가리키는 곳이 다르면 어떻게 될까? 

 

이때는 checkout 처럼 동작한다. 

 

이해를 기반으로 다음의 예시를 생각해보자. 

A commit을 B가 가리키고, 이 때 master branch가 B, Head 가 master 를 가리키는 상황이라고 가정하자. 

이 때 git checkout B 를 통해 detached 상태로 만들고, C 를 commit 하여 Head 를 C 로 옮긴다. 이 때 master 를 c 로 끌고오려면 어떻게 해야 할까? 

 

두가지 방법이 있다. (사실 훨씬 많을 수도 있다.)

1) c의 commit id를 기록해 두었다가 (혹은 reflog로 추후 확인) git checkout maset 혹은 git reset 으로 이동한 후 다시 c로 reset 한다. 

2) c에서 branch를 생성한다. 이 후에는 head 를 다시 master 로 옮겨도 해당 commit은 삭제되지 않는다. 

(branch를 생성한다고 HEAD 가 생성 된 branch를 가리키는건 아니다. 원한다면 checkout으로 manual하게 이동시켜줘야 한다. )


git tag 라는 기능도 있다. 

해당 기능은 branch와는 다르게 정적으로 말뚝처럼 박아놓는 기능이다. (release 버전 표기를 위해서라던가)

tag로 checkout 도 가능하다. 

 

지금 우리가 보고 있는 그래프는 git graph 라는 vs code의 extension 이다. 

CLI 에서 보기 위해서는 git log --oneline -all graph  그래프를 선언해주면 사용 가능하다. 

(git log --oneline (한줄로 짧게), -all(Head 와 연관이 없는 commit도 모두), graph(그래프로 visualization))

뭐 위와 동일하다. 

볼때는 Head -> main 로 head 가 가리키는 위치만 보고 뒤에는 무시하자. (상황 마다 다르다.)


git pull vs git fetch + merge 

전에도 한번 글에서 언급을 했지만, 좀더 실용적으로 간단하게 정리해본다. 

 

git pull은 fetch와 merge를 한번에 한다. 

rebase 에 대해서는 다음글에서 더 설명할 것이지만 간단하게 미리 말하자면 rebase는 자주자주 해주면 더할 나위 없이 간단한 기능이나, 만약 자주 안해줘서 conflict 가 발생할 수 있는 파일의 수정 사항이 많이 쌓이게 되면 하기 어려워진다. 

이로 인해 "pull 이 아닌" fetch로 수정 내역을 먼저 가져와서 merge 전에 시간대 별로 나와 상대의 동 파일에 대한 수정 내역을 볼 수 있다. (아래 그림 참고) pull을 해버리면 바로 merge 가 되어버려서 rebase가 어렵다. 

 

 

 

확인해볼 사항 

- Head 떨어진 상태에서 coommit 어디에 추가 될까? 

- head 로 인해 commit이 지워진 상태에서도 reflog 로 추적 가능할까? 

- git checkout B 를 하려면 git reset master 를 해야할까? 기본 mode 같은 경우, git pull 을 수행하게 되면 git merge commit 을 생성한다. 

Comments