이번 포스팅에선 Git Branch 전략에 대해 이야기해보려 합니다. 브랜치 전략은 총 4가지로, Git Flow, Github Flow, GitLab Flow, Trunk-based development가 있습니다. 이중에서 우리가 프로젝트에서 사용할만한 전략인 Git Flow와 Github Flow에 대해 알아보겠습니다.
브랜치는 우리말로 분기라는 뜻으로, 코드 작성을 위한 별도의 작업공간을 제공하는 수단으로 사용된다. 일반적으로, 브랜치는 작업 완료 시에 메인(마스터) 브랜치로 병합된다. 브랜치를 사용하면, 기능이 서로 분리되기 때문에 실수가 발생할 가능성을 크게 낮출 수 있다. 그 이유는 분기에 대한 변경사항은 다른 개발자의 분기에 전혀 영향을 주지 않기 때문이다.
따라서 브랜치 전략은 소프트웨어 개발 팀이 코드를 작성, 병합 및 배포할 때 채택하는 전략을 의미하게 된다.
여러 개발자가 동시에 작업하고, 동시에 변경 사항을 추가할 때, 애플리케이션에는 많은 오류가 발생할 수 있다. 코드 간의 충돌이 심할수록, Merge 하는 일은 복잡하고 어려워지며 또한, Merge에 시간이 많이 쓰이면 쓰일수록, 원활한 워크플로와 효율적인 DevOps 프로세스에 방해가 된다.
※ DevOps
DevOps는 "Development"와 "Operations"의 합성어로, 소프트웨어 개발과 운영을 조율하고 통합하는 문화, 철학, 방법론이다. 기존의 개발팀과 운영팀 간의 경계를 허물고 개발과 운영의 협업을 강화함으로써 소프트웨어 개발과 배포의 효율성, 안정성을 향상시키는 것을 목표로 한다.
이 때 필요한 것이 바로 브랜치 전략이다. 즉, 소스를 변경할 때 명확한 프로세스를 생성하여 팀이 더 빠른 릴리스와 더 적은 충돌을 달성하기 위해 병렬로 작업을 수행한다는 것이다. 브랜치 전략의 목표는 아래와 같다.
엄밀히 말하면, 브랜치라는 개념은 Git에만 있는게 아니다. 따라서 브랜치 전략에 4가지가 있다는 말보다는 Git Branch 전략에 4가지가 있다고 이야기하는 편이 정확하다. 하지만 여러가지 VCS 도구(버전 관리 시스템)들 중 가장 뛰어나고 가장 널리 쓰이는게 Git이다보니, 일반적으로 브랜치전략이라 함은 Git Branch 전략을 의미한다. Git은 어떻게 분기를 처리하기에 가장 인기있는 VCS Tool이 되었을까?
Git 브랜치의 가장 큰 장점은 '가벼움'이다. 데이터가 일련의 스냅샷으로 구성되기 때문에, 커밋할 때마다 Git이 그 순간의 파일 모양을 스냅샷으로 찍어 이에 대한 참조를 저장한다. 즉, 브랜치는 파일의 복사본이 아니라 포인터라는 것이다. 다른 VCS Tool에선 파일을 저장하는 방식을 사용하는데, 이는 중복 파일이 많을수록 비효율적으로 동작하게 된다. 이러한 점에서 Git이 성능 측면과 공간 측면에서 매우 유리하다고 할 수 있다.
새 브랜치에서 새로운 커밋을 생성한 경우를 생각해보자. 깃에서 브랜치를 생성하고 커밋을 추가하면, 새로운 커밋이 생성되고 해당 브랜치의 포인터가 가장 최근 커밋을 가리키게 된다. 이후 새로운 커밋이 추가되면 해당 브랜치의 포인터는 가장 최신 커밋으로 업데이트된다. 아래의 그림에서와 같이 추가된 커밋은 이전 커밋의 자식 커밋이 되며, master 브랜치의 포인터는 이를 가리키게 된다.
Git Flow 전략은 다시 5가지의 브랜치로 나누어진다.
기능을 개발할 때 feature 브랜치를 만들고, 브랜치를 이동할 때 check out 한다. feature branch를 사용하여 병렬적 개발 체제를 확립할 수 있다. 기능 개발이 마쳐지면 develop 브랜치에 merge 한다. 적어도 현재 단계에선, develop 브랜치를 master나 main 브랜치처럼 생각할 수 있다. 그 이유는 develop 브랜치에는 아직 released 되지 않은 가장 최신의 코드가 유지되기 때문이다. 만약 develop 브랜치에서 필요한 작업을 모두 마쳤다면, develop 브랜치에서 release branch로 분기한다.
release 브랜치에서 문제가 발생한다면, release 브랜치에서 문제를 해결한 후 develop 브랜치로 merge 한다. release 브랜치 코드가 배포까지 정상적으로 완료되었다면, 최종 코드는 develop과 master 브랜치로 merge 한다. 이렇게만 설명하면, develop 브랜치와 master 브랜치를 구분할 필요가 없다고 느낄 수도 있겠지만, 두 브랜치의 역할은 명백히 다르다. 이 내용은 아래 2)번에서 다루도록 하겠다.
마지막으로, hotfix 브랜치는 이미 운영되고 있는 소프트웨어 제품에 긴급하게 수정이 필요한 심각한 버그, 보안 취약점, 또는 기능적인 결함 등을 해결하기 위해 사용한다. hotfix는 정기적인 업데이트나 다음 버전 출시를 기다리지 않고, 신속하게 적용되어야 하는 긴급한 수정 작업을 의미한다. hotfix 브랜치에서 문제가 해결되면, develop 브랜치에서 master 브랜치 순으로 merge 된다.
develop 브랜치는 개발단계에서 필요한 메인 브랜치로, 말 그대로 개발 작업이 진행되는 곳이다. 새로운 기능을 개발하고, 버그를 수정하고, 코드를 리팩토링하는 등의 작업이 develop 브랜치에서 이루어질 수 있다. 그렇기 때문에 develop 브랜치는 지속적으로 업데이트되지만, 기능의 안정성이 보장되지는 않는 상태이다. 즉, 최신 코드가 merge되는 브랜치이긴 하나, 개발 과정에서의 실험적인 기능이 추가될 수도 있기 때문에 배포되어 실제로 운영되고 있는 안정화 버전과는 얼마든지 내용이 다를 수 있다.
master 브랜치의 경우, 방금 이야기했듯, 제품의 안정된 버전이 유지되는 메인 브랜치이다. 즉, 배포 가능한 상태의 코드가 있는 브랜치로, 실제로 배포되는 코드는 master 브랜치에서 가져온다. 따라서 master 브랜치에는 안정적이고 테스트가 완료된 버전의 코드만이 반영되어야 한다.
한마디로 정리하면, develop 브랜치에서 완료된 기능들이 테스트 및 QA(Quality Assurance)를 거쳐 안정성이 검증되면 master 브랜치로 병합된다는 것이다. 더 쉽게 이야기하면, master 브랜치는 운영 환경의 코드를, develop 브랜치는 개발 환경의 코드를 유지한다.
① 브랜치 관리의 명확성
② 배포 안정성
③ 협업 효율성
④ 버전 관리와 롤백
⑤ 유지 보수에 용이
① 복잡성
② 다소 높은 진입장벽
③ 느린 릴리스
④ 팀 규모에 대한 제한
⑤ 유연성의 한계
Github Flow는 깃허브(GitHub)를 기반으로 한 간단하고 유연한 개발 워크플로우로 주요 목표는 신속한 배포와 효율적인 협업을 지원하는 것이다. Github Flow는 Git Flow와 달리 단일 브랜치를 사용하여 개발하는데, 이는 하나의 버전이 만들어지면 바로 배포될 수 있다는 의미이다.
① Branch 생성
② Commit 작성
③ Pull Request
④ 리뷰 및 피드백
⑤ 병합
⑥ 배포
① develop 브랜치와 main 브랜치
② release 브랜치
③ hotfix 브랜치
① 간단하고 직관적인 구조
② 지속적인 배포
③ 유연성과 빠른 피드백
④ 충돌 최소화
① 대규모 프로젝트에 제한적
② 배포 위험성
③ 배포 관리의 어려움
따라서 본인이 진행할 프로젝트의 규모, 배포방식, 협업 방식, 프로젝트의 지속성 및 유지보수의 필요성, 개발자의 경험과 선호도 등의 여러 요소를 복합적으로 고려하여 Git 브랜치 전략을 알맞게 선택할 수 있어야 한다.
[이미지 출처]