아직도 몰랐던 git, 기초를 잡아보자

surinkwon·2023년 11월 19일
1

깃 기초 정리가 필요하다고 생각한 이유

부스트캠프 그룹 프로젝트를 하면서 깃과 관련된 이슈가 발생했다. 예상하지 못한 문제라 굉장히 당황스러웠고, 어찌저찌 수습은 했지만 깔끔하게 해결되지는 않았다.

그 동안 git을 잘은 몰라도, pull, merge 등의 개념은 알고 있다고 생각했다. 또 부스트캠프에서 fetch, rebase도 사용하게 돼서 어떤 방식으로 동작하는지 이해하고 있다고도 생각했다. 그런데 전혀 아니었다. 문제가 발생했을 때 왜 발생한 것인지도 잘 알지 못했고, 그래서 해결도 제대로 하지 못했다. 그래서 발생한 문제와 관련된 기본 개념들을 학습해보고자 한다.

remote

  • 인터넷이나 네트워크 어딘가에 있는 저장소
  • 리모트 저장소 관리는 저장소 추가, 삭제, 브랜치 관리, 추적 등을 모두 포함한다.
💡 리모트 저장소가 로컬에 존재할 수도 있다. 항상 네트워크를 통해 멀리 떨어져있어야 하는 게 아니다. 지금 있는 저장소가 아니라 떨어져 있는 저장소라고 생각하면 될 것 같다.

리모트 저장소 확인

git remote를 통해 프로젝트에 등록된 리모트 저장소 확인 가능하며, 리모트 저장소의 단축 이름을 보여준다. 저장소를 clone하면 origin이라는 리모트 저장소가 자동으로 등록된다.

origin은 github에 생성된 레포지토리임을 알 수 있다.

  • 위처럼 클론 후 저장소로 이동해 git remote로 확인하면 origin을 볼 수 있다.

  • -v 옵션을 통해 단축 이름 + URL 확인 가능

리모트 저장소는 여러 개가 될 수 있다. 저장소를 추가하려면 git remote add [remote 별칭] [url]명령어를 사용하면 된다.

fetch

로컬에는 없지만 리모트 저장소에는 있는 모든 데이터를 가져오는 명령어

git fetch [remote 별칭] [refspec ...]

  • remote 별칭 기본 값은 origin

데이터를 가져오기만 할 뿐 따로 merge하지는 않아서 이후 수동으로 merge해야 한다. → 리모트 저장소에 있는 파일이 merge되기 전까지는 로컬 저장소에 반영되지 않는다.

fetch 후 git diff 명령어를 통해 리모트 저장소와 로컬 저장소의 차이를 확인할 수 있다. 따라서 fetch하여 변경 사항을 확인한 후 pull 하는 것이 안전하다.

fetch 동작 확인

github에 test-branch를 만들고 이를 로컬에 clone 받았다. 이후 test-branch에 fetch_test.txt 파일을 만들고 커밋했다. 그 다음 fetch를 진행해보자.

fetch 이전

  • 폴더 내부
  • .git/objects 내부
  • git graph

fetch 이후

  • 폴더 내부
  • .git/objects 내부
  • git graph
  • git diff

git fetch origin을 하면 이처럼 fetch_test.txt 파일이 생기지는 않지만, 변경 사항과 관련된 object와 fetch_test.txt를 작성한 커밋 내역이 생성된 것을 확인할 수 있다.

git diff HEAD [변경된 커밋], git diff [변경된 커밋]을 통해 달라진 점을 확인할 수 있다.

이 상태에서 merge 또는 rebase를 하면 커밋이 반영된다.

pull

리모트 저장소에서 데이터를 가져오고(git fetch) 자동으로 로컬 브랜치와 merge하는 명령어

실제로 git pull은 git fetch와 git merge를 순서대로 진행한 것이다.

git pull [options] [repository] [refspec ...]

  • repository는 리모트 저장소의 이름이어야 한다.
  • refspec은 대개 리모트 저장소의 브랜치 이름이다.
  • git pull origin master는 origin이라는 리모트 저장소의 master 브랜치를 pull 하겠다는 의미
  • repository와 refspec의 기본 값은 현재 브랜치가 tracking하고 있는 리모트 저장소와 브랜치

git pullgit fetch 후, 갈라진 브랜치를 일치시키기 위해 git rebase 또는 git merge를 호출한다. fetch 후 항상 rebase하도록 하고 싶으면 git config pull.rebase true 명령어를 통해 설정하면 된다.

merge

한 브랜치에서 다른 브랜치로 합치는 방법 중 하나

git merge [병합할 브랜치]

merge 방식

fast-forward

  • 머지할 브랜치가 가리키는 커밋이 현재 브랜치가 가리키는 커밋에 기반한 브랜치일 때 일어나는 머지 방식(현재 브랜치가 머지할 브랜치의 조상)
  • 현재 브랜치의 포인터를 머지할 브랜치가 가리키는 커밋으로 이동시킨다.

fast-forward 동작 확인

fast-forward 동작을 보기 위해 test-branch에서 fast-forward 브랜치를 파고 파일을 생성해보자.

이후 add 및 commit 하고 그래프를 보면 다음과 같다.

이제 test-branch에서 git merge fast-forward로 머지하면 메시지에 Fast-forward라고 나오며, 새로운 커밋이 생성되지 않고 test-branch의 head만 이동한 것을 볼 수 있다.

3-way-merge

  • 현재 브랜치가 가리키는 커밋이 머지할 브랜치가 가리키는 커밋의 조상이 아닐 때 일어나는 머지 방식
  • 두 브랜치가 가리키고 있는 커밋들과 그 커밋들의 공통 조상 커밋을 사용해 새로운 커밋을 만든 후 현재 브랜치의 포인터를 새로 만든 커밋으로 이동시킨다.

3-way-merge 동작 확인

test-branch에서 파일을 하나 만들고 커밋하고, one-branch를 만들어서 그 내부에서도 파일을 만들고 커밋했다. 이후 이 둘을 머지하니 다음과 같이 새로운 커밋이 만들어지면서 머지된 것을 확인할 수 있다.

메시지에도 Fast-Forward가 아니라 다른 메시지가 쓰였다.(ort는 Ostensibly Recursive Three-way를 의미한다.)

test-branch로부터 one-branch를 만들었지만 test-branch에서 새로운 커밋을 했으니 더 이상 test-branch가 가리키는 커밋은 one-branch 커밋의 조상이 아니다. 따라서 머지 커밋이 생성되고 합쳐지게 된다.

rebase

한 브랜치에서 다른 브랜치로 합치는 방법 중 하나

git rebase [병합할 브랜치]

병합할 브랜치에 있는 변경 사항을 patch로 만들고(묶음으로 관리하는 것) 이를 현재 브랜치에 적용시키는 방식

현재 브랜치와 병합할 브랜치가 나뉘기 전의 공통 커밋으로 이동한 후, 그 커밋부터 현재 브랜치가 가리키는 커밋까지 diff를 차례대로 만들어 임시 저장한다. 그 후 rebase할 브랜치(현재 브랜치)가 병합할 브랜치가 가리키는 커밋을 가리키게 하고 저장해 놓은 diff를 차례대로 적용한다.

rebase 동작 확인

rebase 브랜치를 만들고 파일을 생성해 커밋했으며, test-branch에도 다른 파일을 하나 생성해 커밋했다.

그래프를 보면 역시 더 이상 test-branch가 가리키는 커밋이 rebase 커밋의 조상이 아님을 알 수 있다.

git rebase [생성한 브랜치(여기에선 rebase)] 명령어를 통해 rebase 한 결과 머지가 되는 것이 아니라 아래처럼 공통 커밋으로부터 rebase 브랜치의 커밋과 test-branch의 커밋이 차례대로 적용된 것을 확인할 수 있다.

마무리

git pull, fetch, rebase, merge 등에 대해 알아보았다. 이렇게 정리하기 전까지 pull이 fetch와 merge를 실행한 것임을 알지 못했다. 이를 통해 내가 얼마나 git에 대해 모르고 있었는지 깨닫게 됐다. 그렇지만 이번 학습을 통해 앞으로 문제가 발생해도 당황하지 않고 잘 해결할 수 있을 거라 생각한다.

참고 자료

profile
함께 일하고 싶은 프론트엔드 개발자가 되고 싶습니다.

0개의 댓글

관련 채용 정보