branch merge 방법들에 대해 설명하기 전에 간단히 브랜치(branch)와 머지(merge)에 대해 설명하고 넘어가 보도록 하겠다.
브랜치는 하나의 코드 관리 흐름이라고 생각하면 된다. 마스터 브랜치(master branch)는 레포지토리를 만들고 커밋을 하면 자동으로 생기는 기본 브랜치이다.
merge에 관한 좀더 깊은 이야기를 해보도록 하겠다. merge를 하면 새로운 커밋이 생긴다고 했다. 그리고 merge를 통해서 생격난 커밋을 머지 커밋(merge commit)이라고 부른다.
master 브랜치에서 premium 브랜치를 merge해서 검은색의 머지 커밋이 생긴 것을 알 수 있다. 하지만 merge를 한다고 항상 이렇게 새로운 커밋이 생기는 건 아니다.
왼쪽 이미지처럼 현재 master 브랜치에 있다가 git merge premium을 실행하면 오른쪽 이미지처럼 바뀌게 된다. 이렇게 새로운 커밋이 생기는 게 아니라 단지 브랜치가 이동하게 되는 머지를 'Fast-forward 머지'라고 한다. Fast-forward는 어떤 영상이나 소리를 빨리감기(앞으로 감기)한다는 뜻인데, 지금 master 브랜치가 더 최신 커밋으로 이동하는 모습이 빨리감기와 비슷하다.
커밋 히스토리에서 같은 선(line) 상에 있는 브랜치를 merge할 때 Fast-forward 머지가 이루어진다. 전에 master 브랜치와 premium 브랜치가 둘다 같은 선 상에 있었다. 바로 이런 경우를 말한다.
위 그림처럼 두 브랜치가, 커밋 히스토리 상에서 분리된 2개의 선에 각각 존재할 때 merge를 하면 머지 커밋이 새롭게 생긴다. 그리고 이런 머지를 '3-way merge'라고 한다. 이름이 3-way인 이유는 지금 1,2,3 표시한 3가지 커밋을 고려해서 머지를 하기 때문이다.
3-way merge는 자신만의 방식을 갖고 이 3가지 커밋을 기준으로 머지 커밋을 자동으로 만들어 낸다.
| 경우 | base | master | premium | 머지 결과 | |
| case1 | A | A | B | -> | B |
| case2 | 1 | 2 | 1 | -> | 2 |
| case3 | "hello" | (공백) | "hello" | -> | (공백) |
| case4 | "bye" | "fighting" | "please" | -> | Conflict 발생! |
각 컬럼에 대해서 설명해 보도록 하겠다. (모든 커밋에 sample.txt 파일이 있다고 가정한다.)
각각의 경우 왜 표와 같은 머지 결과가 발생했는지 알려주도록 하겠다.
Pull Request란, 다른 GitHub 사용자들에게 자신의 작업한 내용을 검토하고 머지해 달라고 요청하는 GitHub의 기능이다. 줄여서 PR이라고도 한다. PR을 활용하면 다른 개발자들에게 여유가 될 때, 코드를 검토해 달라고 피드백을 요청할 수 있다. 특정 시간에 맞추지 않아도 되고, 서로의 의견을 자유롭게 교환할 수 있으며, 더 효율적이고 품질 놓은 코드를 작성할 수 있다.
merge pull request 녹색 버튼을 누르면 선택된 두 브랜치를 머지하게 된다. GitHub에서 두 개의 브랜치를 머지하는 방법은 총 3가지이다.
Merge commit 방식은 두 브랜치의 변경 사항을 모두 유지하면서 병합한다. 이 방식을 사용하면, 각 브랜치의 변경 사항이 과거의 커밋으로 보존되고, 새로운 커밋이 추가되어 최종 병합이 완료된다.
장점
브랜치의 히스토리를 모두 유지하면서 변경 사항을 병합할 수 있다는 장점이 있다. 이를 통해 프로젝트의 진행 상황을 명확하게 이해하고 추적할 수 있다. 또한, 모든 커밋들의 커밋 아이디가 바뀌는 경우가 없기 때문에 다음에 다룰 squash와 rebase 방식에 비해 비교적 사용이 쉽다.
단점
커밋 히스토리가 복잡해진 수 있다. 다양한 브랜치에서 여러 작업이 이루어지면 커밋 로그가 빠르게 복잡해질 수 있다.
Squash and Merge는 브랜치에서의 모든 변경 사항을 하나의 커밋으로 압축하여 병합하는 방식이다. 이 방식은 각각의 커밋에서 발생한 모든 변경 사항을 병합 후에 하나의 새로운 커밋을 생성한다. 위 이미지에서 3rd-4th-5th 커밋이 하나의 커밋 feature/f1으로 합쳐져서 병합이 된 것을 확인할 수 있다.
장점
커밋 히스토리를 간단하게 유질할 수 있다는 장점이 있다. 각 커밋이 특정 Pull Request를 대변하게 되고, 그 의미를 이해하기 쉽게 된다. 즉, 커밋 하나하나가 완성된 기능을 의미하게 된다. PR에서 발생한 자잘한 문제들을 숨기고, 그 PR에서 가장 중요하고 필요했던 내용들만 압축하여 담게 된다.
단점
작업의 상세한 이력을 잃게 된다. 각 커밋에 대한 개별적인 맥락이나 작업작의 정보 등이 포함되지 않기 때문에 추후 문제 해결이 어려울 수 있다. 또한 기존의 작업 커밋의 아이디들이 하나로 합져치며 사라지고 새로운 커밋 아이디가 생성되기 때문에 여러명이서 해당 브랜치를 기반으로 작업을 수행하고 있었다면 병합이 이뤄지는 경우 복잡한 문제를 야기할 수 있다.
Squash 방식을 사용한다고 해서 모든 커밋 내역이 날아가는 것은 아니다. Git 자체가 아닌 GitHub에는 해당 커밋 기록들이 모두 남아있기 때문에 Pull Request를 검색해서 해당 작업의 커밋 히스토리를 확인할 수 있다.
Rebase and Merge는 현재 브랜치를 target 브랜치에 재위치(rebase)시킨 후 병합하는 방식이다. 이는 target 브랜치의 커밋 위로 현재 브랜치의 모든 커밋을 옮겨 놓는 것과 같다. 이렇게 되면 커밋 히스토리는 선형적으로 유지된다.
장점
깨끗하고 선형적ㅇ니 커밋 히스토리를 만들어 준다는 장점이 있다. 이로 인해 히스토리 파악 및 코등의 변화 이해가 더욱 쉬워진다.
단점
관련된 커밋 ID들이 모두 바뀌게 되어 혼란을 초래할 수 있다. 이는 특히 브랜치가 크게 분기된 경우에는 복잡하고 어려울 수 있다. 여러 개발자가 동시에 작업을 수행한 경우에는 rebase 방식이 복잡한 충돌을 일으킬 수 있다. 추가로 PR별로 다른 기능으로 나뉘어 있던 작업 이력이 하나의 선형적인 히스토리로 합쳐지는 단점이 있다. 즉, 특정 기능이 어디서부터 어디까지의 커밋으로 구현되었는지 알기 어려워진다.
브린치 전략은 간단히 말해 여러 개발자가 하나의 저장소를 만들어 사용하는 환경에서 저장소롤 더 효율적으로 활용하기 위한 작업 흐름이라고 생각하면 된다. 브랜치의 생성, 삭제, 병합 등 Git의 유연한 구조를 활용해서, 각 개발자들의 혼란을 최대한 줄여 다양한 방식으로 소스를 관리하는 역할을 한다.
이러한 상황을 최소화하기 위한 것이 브랜치 전략이다.
Git Flow는 크게 Main, Develop, Supporting 브랜치로 구분하여 브랜치를 관리한다. Supporting 브랜치는 또 다시 Feature, Release, Hotfix 브랜치로 나뉜다.
feature > develop > release > hotfix > master
왼쪽으로 갈수록 포괄적인 가지이며, master 브랜치를 병합한 경우 그 왼쪽에 있는 hotfix 등 모든 가지들에 있는 커밋들도 병합하도록 구성하게 된다.
master : 라이브 서버에 제품으로 출시되는 브랜치develop : 다음 출시 버전을 대비하여 개발하는 브랜치feature : 추가 기능 개발 브랜치release : 다음 버전 출시를 준비하는 브랜치hotfix : 버그를 수정하는 브랜치메인 브랜치는 master 브랜치와 develop 브랜치 두 종류를 의미한다. master 브랜치는 배포 가능한 상태만을 관리하는 브랜치를 의미하며, develop 브랜치는 다음에 배포할 것을 개발하는 브랜치이다. 즉, develop 브랜치는 통합 브랜치의 역할을 하며, develop 브랜치를 기반으로 개발을 진행하게 된다.
master 브랜치에서 develop 브랜치를 만들고, develop 브랜치에서 다시 feature 브랜치를 나눠 작업을 하고 있는 것을 알 수 있다. develop 브랜치에는 기존에 잘 작동하는 개발 코드가 담겨있으며, feature 브랜치는 새로 변경될 개발코드를 분리하고 각각 보존하는 역할을 한다. 즉, feature 브랜치는 기능을 다 완성할 때까지 유지하고, 다 완성되면 develop 브랜치로 머지하고 결과가 좋지 못하면 버리는 것을 선택한다.
배포를 위한 최종적인 버그 수정 등의 개발을 수행하는 브랜치이다. develop 브랜치에 버전에 포함되는 기능이 머지가 되었다면 QA를 위해 develop 브랜치에서부터 release 브랜치를 생성한다. 배포 가능한 상태가 되면 master 브랜치로 병합하고, 출시된 master 브랜치에 버전 태그를 추가한다.
버그를 잡는 동안에도 develop 브랜치에서 작업을 계속 할 수 있다. 이 때 hotfix 브랜치에서의 변경 사항을 develop 브랜치에도 머지하여 분제가 되는 부분을 처리해줘야 한다. hotfix 브랜치는 보통 버그를 고치기 위해 생성되는 브랜치이므로, 버그를 해결하면 보통 제거하는 일회성 브랜치이다.