Git은 알려진 툴 중 가장 널리 사용되고 있는 형상관리 및 협업을 위한 도구이다. 개인이 혼자 프로젝트를 진행한다면 자신이 작성한 코드는 곧바로 메인 master 브랜치에 push와 commit을 해도 본인만 해당 버전에 대해 알아볼 수 있다면 크게 상관이 없다. 하지만 협업을 하거나 누군가에게 코드를 공유해야 하는 오픈소스 프로젝트라면 단순히 메인 브랜치에 commit만 남발했을 때 언제 리비전 되었고 무엇을 위한 수정이었는가 등에 대한 질문들을 무수히 받게 될 수도 있다. 이런 리스크는 깃 브랜치 전략(Git Branching Strategy)을 통해 어느 정도 예방할 수 있다.
더 많은 방법론이 존재하지만 가장 범용적이라 생각되는 4가지를 선별해 보았다.
Git Flow
우선 Git Flow이다.
위 그림에서 볼 수 있듯 Git Flow는 master, develop, feature, release, hotfix로 나누어 브랜치를 관리한다.
- master : 제품으로 출시될 수 있는 브랜치
- develop : 다음 출시 버전을 개발하는 브랜치
- feature : 기능을 개발하는 브랜치
- release : 이번 출시 버전을 준비하는 브랜치
- hotfix : 출시 버전에서 발생한 버그를 수정하는 브랜치
각 브랜치들의 역할과 전체적인 흐름은 아래와 같다.
- Git Flow는 가장 초기에 master와 develop 브랜치가 존재하며, develop 브랜치에서 상시로 버그를 수정한 커밋들이 추가된다.
- 새로운 기능 추가 작업이 있는 경우 develop 브랜치에서 feature 브랜치를 생성한다. feature 브랜치는 develop 브랜치에서부터 시작한다.
- 기능 추가 작업이 완료되었다면 feature 브랜치는 develop 브랜치로 merge 된다.
- develop에 이번 버전에 포함되는 모든 기능이 merge 된 후 QA를 위해 develop 브랜치에서부터 release 브랜치를 생성한다.
- QA를 진행하면서 발생한 버그들은 release 브랜치에 수정된다.
- QA를 무사히 통과했다면 release 브랜치를 master와 develop 브랜치로 merge 합니다. 마지막으로 출시된 master 브랜치에서 버전 태그를 추가한다.
- fork repository의 작업 브랜치들은 base repository로 Pull Request를 하고 merge가 성공적으로 완료되면 삭제한다.
위 과정들은 우아한 형제들 포스팅에서 참조하였다. 다른 방식으로 각 브랜치들을 이용할 수도 있겠지만 검증된 방식을 먼저 적용해보고 익숙해진 후 필요에 따라 바꾸는 것이 바람직할 듯하다.
이 Git Flow의 장점은 가장 널리 사용되고 있어 관련 자료 검색도 수월하고 수많은 IDE에 플러그인으로 존재하여 접근성이 좋다는 것이다. 반대로 단점은 브랜치가 많아 다소 복잡하다는 것이다. 개인적으로 소규모 프로젝트에 적용했을 때 몇몇 브랜치는 커밋하는 과정을 생략하는 것이 더 생산적이겠다 싶을 때가 있었던 것 같다.
GitHub Flow
이번엔 GitHub Flow이다.
GitHub Flow는 Git Flow를 좀 더 쉽게 변형한 버전으로 보면 된다. 그림에서도 알 수 있듯 1개의 master 브랜치와 여러 feature 브랜치를 필요에 따라 pull request 하는 심플한 방식이다. master는 곧 제품이 릴리즈 되는 가장 최신 버전의 브랜치가 되며, 모든 개발 내용이 master를 중심으로 이루어진다. 전체적인 흐름은 아래와 같다.
- master 브랜치는 언제든 배포가 가능 master는 항상 최신 버전의 상태이며 제품이 릴리즈 되는 브랜치이다.
- 새로운 기능을 추가하거나 버그를 해결하기 위한 브랜치의 이름은 자세하게 어떤 일을 하는지에 대해 작성한다.
- 원격(remote) 브랜치에 수시로 push를 수행해 항상 origin에 자신이 하고 있는 일들을 올려 다른 사람들도 확인할 수 있도록 한다.
- 피드팩이나 도움이 필요할 때, merge 준비가 완료되었을 때 pull reauest를 생성한다.
- 충분한 리뷰 후에 master에 merge 한다.
- master로 push 되어 merge가 수행된 후 즉시 배포해야 한다. 이는 hubot(GitHub에서 지원해주는 배포 자동화 도구)등을 이용해 자동으로 배포가 되도록 설정해 놓는다.
이 전략은 구조가 단순 명료해 처음 형상 관리를 시작한 초보자에게 코드 리뷰가 자연스레 이뤄질 수 있는 구조라는 장점이 있으며, 소규모 팀에서 그다지 많은 버전 관리가 필요하지 않겠다 느껴진다면 이 브랜치 전략을 선택하는 것이 유용할 수 있다. 또한 GitHub에서 제공해주는 기능들을 이용한 배포 자동화를 수행할 수 있다.
다만 아래와 같이 추후 규모가 커지거나 작업이 많아질수록 언제 뭘 했는지 파악하는 것이 복잡해질 수도 있다는 단점이 있다. 아래 예시는 잘 되어 있는 편이다.
GitLab Flow
다음은 GitLab Flow이다.
위 그림에서 알 수 있듯 GitHub Flow와 같이 master와 production 두 개의 브랜치가 구성되어 있는 것을 볼 수 있다. 하지만 GitLab Flow는 GitHub Flow의 최종 master 브랜치까지의 merge 과정 사이 많은 부분이 간소화되어 있어 발생할 수 있는 버그들을 pre-rpoduction 브랜치를 이용해 리스크를 감소시킬 수 있는 전략이다. 다시 말해 Git Flow와 GitHub Flow 중간의 타협점으로 볼 수 있다. 물론 Git Flow나 GitHub Flow보다 GitLab Flow가 더 좋다는 의미는 아니다. 전체적인 흐름은 아래와 같다.
- production브랜치를 둔다. Github flow의 master의 역할을 수행하며 production은 배포만을 담당한다.
- pre-production 브랜치를 두어 개발한 내용을 곧장 반영하지 않고 시간을 두고 반영할 수 있도록 한다.
이 전략은 명료하게 work flow를 표현할 수 있고 Git Flow보다 비교적 단순하다는 장점이 있다. 또한 GitHub Flow에 비해 보다 더 조직적이고 구조화된 구조로 안정성이 있으며 작은 수정 후에도 지속적인 버전 관리 및 배포가 용이하다는 특징도 있다. 하지만 역설적으로 GitHub Flow보다 조금 더 복잡해 소규모 프로젝트에 적용하기 난감한 경우가 있거나 규모가 꽤 있는 프로젝트의 협업 시 혼란을 가중할 수 있다는 단점도 있다. 항상 중간 정도의 절충안은 어느 곳에도 적합하지만 또 애매하다는 특징을 항상 공유하는 것 같다.
Trunk-based development(TBD)
마지막으로 Trunk-based development(TBD)이다. 이 전략은 Google과 FaceBook에서 사용해서 유명해진 브랜칭 모델이기도 하다.
TBD의 특징은 모든 개발자가 트렁크(trunk or master)라는 단일 브랜치에서 직접 모든 작업을 하는 것이다. 이런 구조는 GitHub Flow와 똑같아 보일 수 있다. 하지만 아래와 같은 몇 가지 절대적이고 안전한 규칙들을 지켜야만 한다.
- Pair Programming
페어 프로그래밍(Pair Programming)이란 두 명의 개발자가 한 곳에서 한 명은 코드를 작성하고 한 명은 각 코드행을 검토하는 방식이다. 이 둘 사이의 역할은 뒤바뀔 수 있다. 즉, 작성 중인 코드는 실시간으로 검토될 수 있어 추후 PR 요청이 따로 필요하지 않고 이는 결국 생산성 향상에 기여하게 된다. 뿐만 아니라 더 높은 품질, 코딩 스타일 통일, 지식 공유, 문제 해결에 대한 해결책을 같이 찾음 등의 이점이 있다. - Mob Programming
몹 프로그래밍(Mob Programming)도 페어 프로그래밍과 유사한 방법이며, 전체 팀이 동일한 공간에서 동일한 컴퓨터에서 동일한 작업을 수행하는 개발 방식이다. - 신뢰할 수 있는 빌드가 필요
코드 베이스가 항상 릴리즈가 가능한 상태임을 확신할 수 있어야 한다. 그러기 위해서는 충분한 자동 테스트가 실행되어야 하며, 그렇기 때문에 효과적이고 우수한 테스트 전략 필요하다. - 'Branch by Abstraction' 또는 'Feature Flags'를 사용하여 작업이 완료되지 않는 부분 숨기기
마스터에는 완료되지 않은 코드가 있을 수 있다. 간단한 작업은 Branch by Abstraction을 사용하고, 복잡한 작업은 Feature Flags를 사용할 수 있다. 자세한 내용은 사용법은 링크를 참고 바란다. - 소규모 배치로 개발
팀이 프로덕션 release를 더 자주 할 수 있게 분업을 수행하며, 작업이 며칠이 아닌 몇 시간 안에 완료할 수 있는 소규모 변경사항으로 쪼갠다. - 빠른 빌드
빌드 및 테스트 프로세스는 몇 분 내에 실행되어야 한다. 만약 그렇게 할 수 없다면 시스템 아키텍처에 개선이 필요하다는 것을 의미한다.
이 전략은 브랜치가 존재하지 않는다기 보단 필요시 짧은 수명의 브랜치들을 사용한다고 보는 것이 더 어울리는 것 같다. 하지만 결국 모든 개발자는 항상 프로덕션 환경에서 실행되는 최신 버전의 코드를 가지게 된다.
일반적으로 master에 직접 push를 왜 지양해야 한다는 통념이 있다. 이는 다른 사람의 코드를 리뷰하여 좋은 퀄리티로 우리의 코드 베이스를 유지해야 하며 독립된 branch에서 작업하는 것이 더 효율적이라는 것에서 유래된 것이라 생각한다. 따라서 master는 항상 최적의 상태를 유지해야 하며 항상 릴리즈 가능한 상태이어야 한다는 것으로 귀결된다.
위 논리도 물론 일리가 있다. 하지만 다른 관점으로 바라보았을 때 팀이 아닌 개인의 성과에 초점을 맞춘 것처럼 보이기도 한다. 이는 개발 방법론 중 하나인 워터폴(waterfall) 방식에서 자주 사용되는 접근 방법이다. 결과적으로 자원 효율성(Resource Efficiency)을 통해 각 개인에 맞게 최적화가 필요하고 이로 인한 지연 비용(cost of delay)이 발생한다. 즉, TBD는 팀 전체의 생산 효율성을 극대화시키기 위해 고안된 전략이라 볼 수 있다.
결론
당연한 얘기지만 많은 브랜치 전략들 중 어느 것이 최고의 방식이라 딱 집어 얘기할 수는 없다. 각 프로젝트를 수행하는 팀원들의 성향과 프로젝트 규모와 투입 인원, 기간 등 여러 요소들을 고려해 각 팀과 프로젝트의 색깔에 맞는 최적의 브랜치 전략을 찾는 것이 가장 중요하다. 이는 팀 리더의 중요한 역할 중 하나이다.
참고 자료
https://www.flagship.io/git-branching-strategies/
https://velog.io/@rafael/Git-Branch-Strategy%EA%B9%83-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5
https://techblog.woowahan.com/2553/
https://www.gitkraken.com/learn/git/best-practices/git-branch-strategy
https://www.reddit.com/r/git/comments/6f6f5s/sometimes_we_code_something_truly_beautiful/
https://code-masterjung.tistory.com/73