Git 브랜치 전략 (Git Flow, Github Flow)

Posted by , August 02, 2024
Git

현재 우리 하모니 팀은 PR, 브랜치 전략 등에 대해 논의중이다. 이와 관련하여 가장 핵심이 되는 것이 Git Flow 브랜치 전략이기 때문에, 이를 내 생각과 함께 학습하고 정리해보고자 한다. 학습한 내용들을 글쓰기로 인출(Output) 하며 메타인지 활성화하고, 장기기억화에 큰 도움이 되고자 작성한다.

브랜치는 왜 필요한가?

Github 를 활용하여 작업을 진행하다보면 항상 독립적인 브랜치를 생성하고, 작업을 수행한뒤 PR 을 날려 팀원들의 검토를 받고 머지를 한다. 이 일련의 과정은 관례적으로 사용되는 브랜치 관리 전략인 Git Flow 전략 내에서 발생하는 흐름이다. 왜 우리는 브랜치를 분기하고, 작업을 진행할까? 디폴트 핵심 브랜치인 main 브랜치에서 여러명이 동시에 작업을 진행하고 커밋을 푸시하면 안될까?

alt text

main 브랜치는 이미 서비스가 출시되어 배포된 코드만을 모아두기 위한 브랜치이다. 만약 이 하나의 브랜치에 여러 사람들이 커밋을 푸시하면 어떻게될까? 이 하나의 브랜치에 여러 사람이 한꺼번에 작업을 진행하고 관리한다면, main 브랜치의 소스코드는 정말 불안정한 상태로 관리 될 것이다.

다른 사람이 작업 또한 누군가 내 파일을 건들였을 경우 충돌이 발생할 가능성도 충분하다. 충돌을 만회하고자 뒤늦게 커밋을 롤백하자니, 내가 작업한 모든 내용을 삭제하고 처음부터 다시 작업을 진행해야 할 수도 있다. 브랜치에 작업한 내용을 PR 을 요청할 떄와 달리 내가 작업한 커밋이 충돌이 발생할지 체크할 방법도 존재하지 않기에, 커밋이 엉키고 꼬일 가능성이 충분하다.

더 큰 규모의 조직에서 협업을 진행한다면 큰 문제가 발생할 것이다. 당연하게도 브랜치를 분기하지 않는다면, 각 사람이 main 브랜치로부터 독립적인 브랜치를 파생하여 동시간대에 작업을 진행하지 못하기에 작업 효율이 떨어진다. 오직 main 브랜치 하나에서 수 많은 개발자들에 협업한다면, 내가 작업중인 파일을 누군가 건드릴 수 있게된다. 이는 앞서 서술한 충돌 문제를 야기할 수 있다. 충돌을 만회할 수 있는 가장 안전한 방법은 다른 사람이 main 브랜치에 작업 내용을 푸시할 때 까지 대기하는 것인데, 작업 효율성이 매우 떨어지기에 좋은 방법이 아니다.

또한 여러 기능을 개발하면서 남겨진 커밋 히스토리가 main 브랜치에 뒤죽박죽 섞여서 알아보기 힘든 로그가 쌓이게 된다. 엉켜있고 알아보기 힘든 커밋 히스토리가 쌓여있기에, 기획 변경으로 인해 특정 기능이 필요 없어졌을 때 또는 문제가 발생했을 떄 원하는 시점으로 롤백하기도 어려워진다. 반면 브랜치를 통해 관리했다면 원하는 시점을 가진 브랜치를 활용하여 작업 내용을 적절히 롤백시킬 수 있다.

브랜치 기능을 사용하면 다른 브랜치에 영향을 받지 않는 독립적인 환경에서 기능을 개발할 수 있다. 또한 main 브랜치 하나에서 프로덕션 코드를 관리할 때와 달리, 프로덕션 코드의 안정성과 품질을 향상 시킬 수 있다. 독립적인 브랜치에 개발한 기능을 main 브랜치에 곧 바로 반영할 수 없기 떄문이다. main 브랜치에 내 코드를 기여하기 위해선, PR 을 먼저 요청해야한다. 팀 내 PR 가이드라인을 준수하여 팀원들의 리뷰와 검토를 받고, CI 를 통해 내 코드가 빌드에 성공했는지, 테스트 커버리지가 일정 수준 이상을 만족하여 프로덕션 코드에 반영해도 적절한지를 미리 검토할 수 있다. 또한 충돌이 발생하여 코드가 꼬일 가능성도 거의 0에 수렴한다.


브랜치는 어떻게 관리하는가?

이렇게나 좋은 이점을 제공하는 브랜치 또한 일정한 규칙 없이 마구잡아로 사용한다면 엉키고 알아보기 힘들 수 밖에 없다. 브랜치 생성 및 관리에 대한 명확한 규칙이 없을 경우 "이 브랜치는 어떤 기능을 개발하기 위해 생성된거지?, "어떤 브랜치가 실제 프로덕션 및 배포 코드가 담긴 중요한 브랜치이지?", "PR 은 어디에 요청해서 검토와 승인을 받아야히지?", "이 커밋과 관련한 작업 내용이 담긴 브랜치가 어떤거였지?" 등 수 많은 혼동을 야기할 수 있다.

이를 해결하고자 등장한 것이 Git 브랜치 전략이다. Git 브랜치 전략은 브랜치를 더 효과적으로 관리하기 위한 규칙이자 컨벤션이다. 팀 내 브랜치 규칙을 직접 만들어도 괜찮지만, 전셰게의 수 많은 팀 내에서 관례적으로 사용하고 있는 워크플로우인만큼 꼭 알아둘 필요가 있다. 나는 Git Flow, Github Flow 전략에 대해 학습하도록 한다.

Git Flow 전략

alt text

Git Flow 는 총 5가지 종류의 브랜치로 관리하는 전략이다. 가장 중요한 디밸롭 서버, 프로덕션 서버 실제 코드가 담기고 병합되는 main 브랜치, develop 브랜치가 존재하며, 이 2개의 중요한 브랜치에 병합되기 이전에 각기 다른 목적으로 분기되어 작업을 진행하는 목적을 가진 보조 브랜치들인 feature 브랜치, release 브랜치, hotfix 브랜치 가 존재한다.

main 브랜치와 develop 브랜치는 개발 프로세스 전반에 걸쳐 가장 중요하게 관리되는 브랜치이자, 항상 삭제되지 않고 유지되는 브랜치이다. 이 두 브랜치에 코드를 기여하기 위해선 보조 브랜치를 통해 작업을 진행하고, PR 을 요청해서 승인을 받아야한다. 반면 보조 브랜치(feature, relaese, hotfix) 는 필요할 때 마다 동적으로 생성되는 브랜치로, 제 역할을 다하고 develop (또는 main) 브랜치에 코드를 기여한 뒤에 제 역할을 다했다면 삭제된다. 보조 브랜치 덕분에 팀이 병렬적으로 동시간대에 작업을 진행할 수 있게된다.

main 브랜치

실제 대중에 배포되어 운영되기 직전(또는 이미 운영되고 있는) 프로뎍션 코드들이 담겨있는 브랜치이다. main 브랜치는 develop 브랜치와 마찬가지로 프로젝트 시작부터 끝까지 사라지지 않고 관리되는 핵심 브랜치다. 실제 프로덕션 코드가 담긴 중요한 브랜치인만큼, 후술할 develop 브랜치의 디밸롭 환경에서 수 많은 테스트와 검증을 거친 뒤에서야 main 브랜치에 반영해야 한다.

develop 브랜치

main 브랜치에 병합될 다음 버전 배포를 앞두고 있는 코드들을 담고 있는 핵심 브랜치다. 실제 프로덕션 서버에서 돌아가는 코드들이 main 브랜치에서 관리된다면, 프로덕션 환경과 유사하게 구축한 디밸롭(테스트) 서버내의 코드들은 develop 브랜치에서 관리된다. 즉, develop 브랜치에 기여된 코드들은 테스트(디밸롭) 환경에서 많은 테스트 및 검증을 거친 뒤에야 출시해도 문제가 없다고 판단되었을 때 main 브랜치로 병합된다.

feature 브랜치

하나의 기능을 개발하기 위한 브랜치이다. develop 브랜치로 부터 분기하여 생성하며, 해당 feature 브랜치에서 기능 개발이 완료되면 PR 요청을 날리고, 다시 develop 브랜치로 병합된다.

머지시 주의할 점은 fast-forward 로 머지하지 않고, merge commit 을 생성하여 머지 해줘야한다. 그래야만 히스토리가 특징 기능 단위로 묶이게 된다.

hotfix 브랜치

이름 그대로 특정 문제가 발생했을 때, 해당 문제를 해결하기 위해 분기한 브랜치다. 정의상으로는 이미 배포된 프로덕션에 문제가 발생했을 때, 해당 문제를 해결하고자 분기하는 브랜치이다. 따라서 develop 브랜치가 아닌 main 브랜치에서 생성하고, 문제 해결이 완료되면 main 과 develop 브랜치 모두에 머지한다.

다만, 정의상은 main 브랜치로부터 파생되는 것이 맞지만, develop 브랜치로 부터 파생되어도 전혀 상관없다는 생각이다. hotfix 브랜치가 등장한 이유는 문제를 해결하기 위함에 있는데, 실제 출시 단계가 아닌, 개발 단계에서 이미 문제를 발견했다면 develop 브랜치로부터 파생하고 문제를 해결하면 될 것이다.

release 브랜치

소프트웨어 배포를 준비하기 위한 브랜치이다. develop 브랜치로부터 분기하며, 버전 이름 등의 소소한 데이터를 수정하거나 배포전 사소한 버그를 수정하기 위해 사용된다. 배포 준비가 완료되었다면 main 과 develop 브랜치 모두에 머지한다. 이때, main 브랜치에는 태그를 이용하여 버전을 표시한다. Release 브랜치를 따로 운용함으로써, 배포 업무와 관련없는 팀원들은 병렬적으로 Feature 브랜치에서 이어서 기능을 개발할 수 있게된다. 추가적으로 네이밍은 release/v1.1 과 같은 형태로 생성한다.

다만, release 브랜치는 팀 내 규모에 따라 협의하여 꼭 도입할지 검토해봐도 좋다고한다. 우리 하모니 팀의 경우도 release 브랜치는 도입할 근거가 마땅치 않으며, 불필요한 비용과 복잡성이 높아질 것으로 판단되어 도입하지 않았다.

Github Flow 전략

앞서 서술한 Git Flow 에 비해 Github Flow 는 더 단순해진 구조를 가진다. 다만, Github Flow 전략은 단순함으로 인해 개발이 편하다는 입장을 가진 사람들도 많지만, 내 생각은 다르다. 개인적인 생각으로는 Github Flow 는 매우 단순한 브랜치 구조로 관라하기 떄문에 브랜치 관리가 되려 힘들 것이라는 생각이다. 그러면 Github Flow 에 대해 학습해보자.

alt text

Github Flow 는 위와 같이 main 브랜치와 feature 브랜치 두 종류가 끝이다. 단순히 기능 개발을 하고 master 브랜치에 병합하는 매우 단순한 구조다.

main 브랜치

항상 Stable한 상태여야 한다. 이때, Stable하다는 것은 Main의 모든 커밋은 언제 배포하든 문제 없어야하고, 언제든 브랜치를 새로 만들어도 문제가 없어야 한다. main 브랜치의 모든 커밋은 빌드가 되고, 테스트를 통과해야한다. 이것이 Github Flow가 강제하는 유일한 사항이다.

feature 브랜치

앞서 살펴봤던 git flow 전략의 feature 브랜치와 동일한 역할을 수행하며, 여기서 hotfix 브랜치의 역할 또한 합쳐진 브랜치라고 생각하면 된다. 즉, 기능 개발과 버그 수정 모두 구분없이 동반되어야 하는 브랜치다. 또한 앞선 Git Flow 전략과 달리 Github Flow 에선 main, develop 가 구분되어 있지 않다. 따라서 main 브랜치에 병합되기 이전의 코드들은 언제든 실제 프로덕션 코드에 문제없이 기여될 수 있도록 상시로 완벽하게 준비되어야 한다.

GitFlow 가 과연 적합할까?

어떠한가? 과연 Github Flow 가 단순하다고 해서 좋은 전략일까? 몰론 매우 단순한 구조로 인해 깃허브를 갓 시작한 입문자들에게는 도움이 될 수 있겠다. 하지만 적어도 Git flow 전략처럼 프로덕션과 디밸롭 브랜치가 구분되어 있지도 않다. 또한 feature 브랜치가 버그 수정까지 모두 전담해야 하기에, 역할이 더 커진 구조이다.

개발 팀이 매우 작은 소규모 애자일 팀이고, 제품을 정말 빠르게 출시해도 문제 없다면 Github Flow 를 채택해도 괜찮을 것이다. 하지만 많은 웹 애플리키이션은 테스트와 검토를 디밸롭 서버에서 충분히 검토해야 하기에 develop 브랜치의 필요성이 더 느껴진다. 또한 기능과 버그를 구분하지 않고 브랜치를 파생하고 관리하다보니, 관리가 다소 힘들어질 수 있다는 생각이다.

Scott Chacon 의 의견을 인용하면서 글을 마친다.

장기간 프로젝트가 존재하고, 유지보수를 위한 작업을 수행해야 하는 팀은 Git Flow 가 타당한다. 반면 상시로 정말 빠르게 배포해야 하는 팀은 Github Flow 가 적합하다.

마치며

이 외에도 Gitlab Flow 라는 것을 카카오테크 교육과정에서 학습했는데, 아직은 제대로 학습하지 않도록 한다. Github Flow 는 Git Flow 와 Github Flow 의 중간 정도의 복잡성을 가진 전략이라고 한다. 지금 내 판단으로는 Git Flow 전략을 충분히 학습하고 프로젝트에 도입하는데 전혀 불편함을 느끼지 못했기 떄문에, 향후 Gitlab Flow 도입의 필요성이 느껴진다면 그때 글쓰기를 통해 깊게 학습해보도록 한다.

참고

Haon
꾸준히, 배움에 대한 생각을 글로 정제하기 위한 블로그입니다.
gatsby-starter-haonkakaotech