GitHub에서 브랜치를 생성해서 파일을 생성해 병합(merge)까지 해보았다. 터미널에서 git branch라는 명령으로 브랜치 목록을 조회했는데 main 브랜치 밖에 뜨지 않았다. 여기서 1차 고민...
그래서 인터넷을 검색해본 결과!
git branch 명령어는 로컬 브랜치 목록 조회하는 명령어다.
GitHub에서 생성한 브랜치는 원격 브랜치이고 이것을 터미널에서 조회하기 위해서는 git branch -r을 입력하면 된다. 참고로 로컬과 원격 브랜치 목록을 조회하는 명령어는 git branch -a이다.
아 그렇구나... 잠깐만 리포지토리가 로컬, 원격으로 나뉘는 건 알겠는데 브랜치도 나뉘네..?
여기서 2차 고민...
나는 GitHub에서 원격 브랜치를 생성했는데 이 브랜치를 로컬로 가져올 수가 있나?
또 로컬에서 만든 브랜치를 원격 브랜치로 보낼 수 있나?
로컬 브랜치와 원격 브랜치가 안 맞으면 어떻게 되지?
Git을 사용하면 할수록 궁금증이 더 많아지는 것 같다. 이 궁금증들을 하나씩 해결해나가면 미래의 내가 행복한 표정을 짓고 있을 거 같다. 그러니까 지금부터 Git의 Branch, Merge, Pull Request에 대해 자세히 알아보려고 한다.
GitHub 리포지토리 주소를 clone해서 로컬 리포지토리에 복사한다. 복사 후 해당 로컬 리포지토리로 이동한다.
참고: git clone을 할 경우에 git remote add origin {해당 리포지토리 주소} 명령어가 자동으로 실행되기 때문에 git remote로 조회하면 origin이 뜨는 것을 확인할 수 있다.
clone 후 화면
Branch를 생성한다.
git checkout kj(브랜치명): 브랜치로 이동
git checkout -b kj(브랜치명): 브랜치 생성 후 브랜치로 이동
git checkout -b kj를 입력하면
kj 브랜치가 생성되고 해당 브랜치로 이동한 것을 확인할 수 있다.
그리고 Branch를 조회할 수 있다.
git branch : 로컬 리포지토리 브랜치 확인
git branch -r : 원격 리포지토리(깃허브) 브랜치 확인
git branch -a : 모든(원격+로컬) 브랜치 확인
git branch 결과
로컬 리포지토리 브랜치를 확인할 수 있다.
git branch -r 결과
아직 push를 하지 않았기 때문에 kj 브랜치가 보이지 않는다.
git branch -a 결과
로컬과 원격 리포지토리 브랜치를 확인할 수 있다.
로컬 리포지토리의 kj 브랜치를 원격 리포지토리 브랜치와 연결한다.
git branch --set-upstream-to origin/main (<- 연동할 브랜치명)
그 후에 원격 브랜치에 변경사항이 있을 경우 git fetch 명령어를 통해 변경사항을 로컬 리포지토리로 불러온다.
원격 브랜치에서 변경사항이 있는데 그 사항을 로컬 브랜치의 변경사항과 합치지 않고 로컬 브랜치의 작업물을 올릴 경우 충돌이 일어난다.
이제 로컬의 kj 브랜치에 작업물을 올리고 push까지 진행한다.
push 후 깃허브에 들어가면
로컬에서 생성한 kj 브랜치가 원격 리포지토리에도 적용이 된 것을 확인할 수 있다.
그리고 또 확인할 수 있는 게 Compare & pull request 버튼이다.
pull request를 줄여서 PR이라고도 한다.
브랜치를 생성하고 새로운 기능이나 버그 수정을 위한 코드를 작성한 다음 수정사항을 반영해달라는 PR을 요청하게 된다. 리뷰어는 변경사항을 리뷰하고 승인을 하면 변경사항이 반영된다.
들어가보면
해당 PR에 comment를 남기고 문제가 없으면 Create pull request 버튼을 클릭!
참고: Draft pull request - Draft 모드인 PR 이슈는 merge 버튼이 활성화되지 않는다. 대신 "This pull request is still a work in progress"라는 내용이 뜬다. 아직 작업 중이므로 코드가 merge 될 준비가 아직 되지 않았다는 뜻이다. 즉, Draft 모드를 이용해 작업중인 코드에 대해 토론을 할 수 있다. 웹 페이지를 통해서 코드에 대한 대화를 나누고 작업 사항이 반영된다.
Create pull request 버튼을 클릭하면
다음과 같은 화면이 나온다.
Merge pull request 옆 화살표를 누르면
3가지 merge 방식을 확인할 수 있다.
Merge, Squash merge, Rebase merge 방식의 Merge 방법이 존재한다.
Merge는 일반 Merge다. 브랜치와 브랜치는 이어지고 Merge 된 리포지토리의 히스토리에서 어느 브랜치에서 Merge 되었는지, 이 브랜치에서 어떤 commit들이 있었는지 모두 확인할 수 있다.
user2 브랜치도 kj 브랜치와 동일하게 PR을 했고 두 브랜치 모두 Merge로 했다.
히스토리에서 해당 PR에 대해 상세하게 확인이 가능하다.
브랜치 별로 커밋을 분리해서 유지해준다.
원래 브랜치의 커밋들은 변경되지 않고 계속 유지되어 다른 개발자들의 작업과 공유되는 것에 대해 신경 쓸 필요가 없다.
브랜치가 많아지고, commit도 많아지면 히스토리에 많은 정보가 쌓여 알아보기 힘들다. 따라서 프로젝트의 규모가 크면 클수록 선호되지 않는다고 한다.
Rebase merge는 Merge 할 브랜치의 Commit 내역들을 그대로 옮긴다. 브랜치의 Base를 옮겨 말 그대로 Rebase다. 그래서 브랜치는 이어지지 않는다.
히스토리를 볼 때 깔끔하게 볼 수 있다. 여러 개의 브랜치가 복잡하게 얽혀있지 않고 그냥 디폴트 브랜치 하나의 히스토리만 쭉 읽으면 해당 프로젝트의 히스토리를 이해할 수 있다. 여러 개발자들이 같은 브랜치를 공유할 때 커밋을 합치는 가장 직관적이고 깔끔한 방법이다.
여러 개의 commit을 Rebase merge 했는데 Commit 충돌(conflict)이 일어나면 Merge 하려는 모든 commit에서 충돌이 일어난다.
그래프에서 거미줄처럼 이어지는 브랜치는 없지만 의미 없는 commit도 히스토리에 남는다.
충돌상황에서 다소 복잡하다. 커밋 순서대로 Rebase를 하는데, 각 커밋마다 충돌해소를 순서대로 해야 한다. SourceTree가 가이드하기는 하지만 단순하진 않다.
Squash는 Rebase merge에 옵션을 추가한 느낌이다. Squash 옵션을 적용한 Rebase merge를 Squash merge라고 한다.
Squash merge는 Rebase 하지만 Merge 할 commit들을 하나의 commit으로 뭉친다.
히스토리의 브랜치도 깔끔하게 유지하고 자잘한 commit들을 없애고 의미있는 commit으로만 히스토리를 구성할 수 있다.
Merge에 대한 정보가 부족한 점이 단점이다. 하지만 해당 Merge commit의 설명에 정보를 자세히 명시하면 문제가 되지 않는다고 한다.
파란색 : main(디폴트) 브랜치
주황색 : kj 브랜치 (Merge)
빨강색 : user2 브랜치 (Merge)
보라색 : user3 브랜치 (Squash merge)
초록색 : user4 브랜치 (Rebase merge)
일반 merge는 분기 되었다가 다시 이어지는 것을 확인할 수 있다.
위 그래프로 이해가 잘 되지 않는 것 같아 직접 그려봤다.
commit a, b, c를 합쳐서 새로운 commit abc가 만들어지고 master에 추가된다.
abc는 1개의 parent를 가진다.
모든 commit들이 합쳐지지 않고 각각 main 브랜치에 추가된다.
각 commit은 모두 하나의 parent를 가진다.
일반적인 Merge는 히스토리에 commit 메세지 따로, PR-Merge 정보 따로 2가지가 뜨는 것을 확인할 수 있다.
Squash merge는 commit 메세지와 옆 괄호에 #숫자가 붙음으로써 간단하다. #숫자를 눌러서 PR-Merge 정보를 확인할 수 있다.
Rebase merge는 commit 메세지만 화면에 나온다.
참고
“Github - Merge / Squash Merge / Rebase Merge.” Velog,
https://velog.io/@code-bebop/Github-merge-squash-merge-rebase-merge.