이 글에서는 Git에서 다른 브랜치를 병합하는 명령어인 git merge의 사용법과, merge의 두 가지 방식인 fast-forward, 3-way merge의 특징을 알아볼 것이다.
팀이나 프로젝트마다 각자 세부 규칙은 다르겠지만, main 브랜치 하나에서 직접 작업하는 경우는 매우 드물고, 대부분의 경우 기능 단위로 브랜치를 생성하여 작업한다. 각 브랜치에서 한 작업을 main 브랜치에 반영하기 위해 브랜치를 병합할 때 git merge 명령어를 사용한다.
예를 들어 53번 이슈 해결을 위해 iss53 브랜치를 만들고 해당 브랜치에서 작업을 완료한 뒤 main 브랜치에서 iss53 브랜치를 병합하고자 한다면, 다음의 코드를 사용하면 된다.
# 현재 iss53 브랜치에서 막 마지막 커밋을 마쳤다고 가정
$ git checkout main # main 브랜치로 체크아웃
$ git merge iss53 # iss53 브랜치를 병합
merge에는 fast-forward와 3-way merge 두 가지 방식이 있다. 이 두 방식을 알아보기 위해 상황을 먼저 가정하자. 개발자는 이슈 53번을 해결하기 위해 iss53 브랜치를 생성하여 작업중이었다(그림1). 그런데, 지금 개발중인 것보다 시급하게 작업해야 할 이슈가 발생하여 hotfix 브랜치를 생성하고 해당 브랜치에서 작업을 마쳤다(그림2). 작업한 내용을 main 브랜치에 반영하기 위해 hotfix 브랜치를 merge(fast-forward)했다(그림3). hotfix 브랜치는 지우고, 다시 iss53 브랜치로 돌아가 남은 작업을 완료했다(그림4). 마찬가지로 작업을 main 브랜치에 반영하기 위해 iss53 브랜치를 merge(3-way merge)했다(그림5). 이 두 merge가 어떻게 다른지 확인해보자.
(그림 1) iss53 브랜치에서 개발중
(그림 2) hotfix 브랜치에서 급히 개발완료
(그림 3) main 브랜치에서 hotfix 병합 완료 (fast-forward)
(그림 4) iss53 브랜치에서 남은 작업 완료
(그림 5) main 브랜치에서 iss53 병합 완료 (3-way merge)
현재 브랜치가 가리키는 커밋이 병합 대상 브랜치가 가리키는 커밋의 조상인 경우 fast-forward가 진행된다. 예시에서는 현재 브랜치가 main, 병합 대상 브랜치가 hotfix에 해당한다. 그림 2에서처 확인할 수 있듯이 hotfix 브랜치가 가리키는 커밋(C4)은 main 브랜치가 가리키는 커밋(C0)에 기반한다. 이러한 경우, 그림 3에서처럼 main 브랜치가 가리키는 커밋이 hotfix 브랜치가 가리키는 커밋과 같아질 뿐 새로 커밋을 생성하지는 않는다. 이처럼 브랜치가 가리키는 커밋만 최신의 것으로 변경시키는 과정을 fast-forward라고 한다.
반면, 그림 4에서는 현재 브랜치가 가리키는 커밋이 병합 대상 브랜치가 가리키는 커밋의 조상이 아니다. 이런 경우 공통 조상 커밋(C0)과 각 브랜치가 가리키는 커밋(C4, C5)을 모두 고려한 3-way merge가 진행된다. 3-way merge에서는 공통 조상 커밋을 기준으로 각 커밋의 변경사항을 반영하여 새로운 커밋(C6)을 생성한다. 두 커밋이 서로 다른 부분을 변경한 경우 각 변경을 반영하지만, 같은 부분을 변경한 경우 변경사항이 충돌했다고 하며 conflict가 발생한다. 이 때에는 Git이 어떤 변경사항을 적용할 지 선택하기 어려우므로, 개발자가 직접 결정해주어야 한다.
[참고]