[VCS] Git Branching Strategy – Git flow

글쓴이 Engineer Myoa 날짜

들어가기에 앞서

학생 시절 VCS에 무덤덤했고, 단순히 master 브랜치에서 반복되는 커밋으로 체계적이지 못한 버전관리를 하고 있었습니다.

어느 순간 현업에서 일을하며 자연스럽게 Git-flow를 적용하고 있었고, 오늘은 Git Branching Strategy 중 하나인 Git flow에 대해 나누고자 합니다.

조금 더 정확하게는, 개념과 workflow를 확실하게 기억하고자 기록을 남기는 과정으로 생각합니다.

 

 

Git-Flow

여러 Git branching strategy 중 흔하게 사용되는 전략으로 Git flow가 있습니다.

보통 Git flow를 설명할 때 아래 이미지를 빼고 말하면 섭섭합니다. 정말 유명한 그림.

 

ref. https://nvie.com/posts/a-successful-git-branching-model/

이 이미지는 정말 감사하게도, Vincent Driessen 라는 저자가 CC-BY-SA 라이센스로 공개한 이미지입니다.

따라서 2차 가공이 가능하므로, 상세하게 파트별로 나누어서 보도록 하겠습니다.

 

 

메인 브랜치

Git flow에서는 2개의 영구적인 메인 브랜치를 가지고 있습니다.

바로 master, develop 브랜치입니다.

 

마스터 브랜치 (master branch)

이 브랜치의 HEAD는 production-ready 상태인 커밋을 가리켜야 합니다. 릴리즈시에 이 브랜치를 참고합니다.

master 브랜치는 Git working directory를 initialize (git init)시 기본적으로 생성되는 브랜치입니다.

따라서 가장 첫 커밋은 master 브랜치에서 이루어지고 이를 develop 브랜치로 merge 합니다.

(master) $ git commit
(master) $ git checkout develop
(develop) $ git merge master

 

디벨롭 브랜치 (develop branch)

이 브랜치의 HEAD는 다음 릴리즈에 반영될 변경 사항들이 모두 포함되어 있는 커밋을 가리켜야 합니다.

이 develop 브랜치에서 stable 하다고 느끼거나, 혹은 차기 릴리즈(정기 배포 등) 일정이 정해져 있을 시에 master 브랜치로 merge 합니다.

(develop) $ git checkout master
(master) $ git merge develop

 

보조 브랜치

보조 브랜치는 병렬적으로 feature를 개발하는 환경에서 사용합니다.

1인 개발에서는 사용하지 않는 경우도 있습니다. 하지만 1인개발이라도 병렬적으로 feature 를 개발하는 경우에는 이 보조 브랜치 전략을 따라가는것이 좋습니다.

이 보조 브랜치에는 feature, release, hotfix 브랜치가 포함됩니다.

보조 브랜치는 브랜치 명명법을 가지고 있습니다. 강제적인 사항은 아니지만 컨벤션이 있는 이유가 있습니다.

BTS(Bug Tracking System)에서는 하나의 티켓이 발행되면 Sequence가 증가하게 되는데, 이 Sequence를 보조 브랜치의 이름으로 사용합니다.

 

e.g EXAM-001 : log-in frontend do not showing our logo

(develop) $ git checkout -b feature/EXAM-001

사실 feature는 자유로운 편인데, 여러 팀원들과 함께하는 프로젝트에서는 문맥을 일치시키는 편이 더 좋습니다.

 

 

보조 브랜치들은 제한적인 lifetime 을 가지고 있습니다. 따라서 merge 이후 언젠가는 없어지게 됩니다.

(대신 태그가 남기 때문에 태그 다는 것을 습관화 합시다!)

그러면 각 브랜치들이 어떤 역할을 하는지 알아보겠습니다.

 

피쳐 브랜치 (feature branch)

새로운 기능, 새로운 페이즈(Phase), 혹은 서스테이닝(Sustaining), 유지보수 등에 해당 하는 작업을 진행할 때 feature 브랜치를 이용합니다.

feature 브랜치는 개발자의 repository 에만 존재하고, origin에는 존재하지 않는것이 일반적입니다.

이 부분이 약간 모호하긴 한데 깔끔한 repository 를 운영하려면 위와같이 하면 좋을 것 같긴 합니다. 

 

라이프사이클:

(branch off from) develop -> feature

(merge back into) feature -> develop

 

개발이 끝난 후 feature 브랜치의 라이프 사이클대로 develop 브랜치에 merge 를 하게 됩니다.

git merge 명령어는 기본값으로 커밋들을 plain 하게 합쳐줍니다. 마치 내가 develop 에서만 작업을 했던 것처럼. 하지만 no-ff(no fast-forward) 를 사용하면 작업했던 브랜치를 명시적으로 나타내고, merge시에는 반드시 새로운 커밋을 만들어 기점을 둡니다.

커밋시 no-ff 파라미터는 몇 가지 이점을 줍니다.

 

커밋 그래프상 명확하게 feature의 범위임을 알 수 있고,

이후 무언가 잘못 됐을 때 찾기가 수월해집니다.

만약 해당 지점을 찾기 위해 모든 커밋로그를 확인해야 한다면, 그거대로 새로운 비용이 들기 때문이죠.

 

 

릴리즈 브랜치 (release branch)

릴리즈 브랜치는 이름 그대로 릴리즈를 위한 브랜치입니다.

단, 릴리즈 브랜치에서는 목표했던 산출물 자체에 큰 변화가 있어서는 안됩니다.

빌드 도구의 설정 파일 내의 버전업(pom.xml, build.gradle 등 에서의 application version) 이나, 주석의 일부를 수정하는 정도의 내용만을 수정해야 합니다.

 

하지만 위 문단에서 목표했던 산출물 이라고 한 것처럼, 코드의 변화가 생길 수도 있습니다.

  • 릴리즈 예정인 기능에 버그가 있었음을 깨달아 수정을 하게 됩니다.
  • 목표했던 기능은 QA까지 완료되었는데, 추가로 이번 릴리즈에 이 기능도 같이 나가면 좋겠다 싶어 포함합니다.

릴리즈 단계해서는 목표했던 기획 건들이 명확하게 완료가 되었는지에 충실해야 합니다.

QA까지 완료된 상태이기 때문에, 비즈니스 로직등이 수정될 경우 진행한 QA가 의미가 없어지게 됩니다.

따라서 치명적인 버그로 운영에 차질이 생기는 일이 아니면 release 브랜치에서는 큰 변화를 주어서는 안됩니다.

 

라이프 사이클:

(branch off from) develop -> release

(merge back into) release -> develop, release -> master

 

versioning 등 release 에서 진행해야 할 내용을 한 이후에 repository 에 반영하고, 실제 배포까지 하는 일련의 과정들을 합쳐 release engineering 이라고 합니다.

release engineering 을 위해 다음과 같은 수순을 따릅니다.

1) develop 으로 부터 release 브랜치 만들기

(develop 으로부터 release 브랜치 체크아웃)

(version 정보 수정 및 bugfix)

(develop) $ checkout -b release-1.0

# ... Modify project versioning related or bugfixes

(release-1.0) $ git commit -m "Deploy version 1.0"

release 브랜치에서는 위와 같이 version을 붙여 명명할 수도 있고, BTS의 event ticket을 받아 명명할 수도 있습니다.
결국 tag를 붙이고 release 브랜치는 삭제되기 때문에 어느 쪽을 고르던지 문제는 없습니다.

 

 

2) release -> develop, release -> master

먼저 release 브랜치의 내용을 master 로 merge 합니다. 아까 보았던 –no-ff 파라미터는 옵셔널 값입니다.

 

merge 한 이후 tag를 붙여줍니다.

 

master 브랜치의 HEAD는 운영될 버전의 production 입니다. 따라서 탐색과 마킹용도로 사용하기 위해 tag 를 붙여줍니다.

(release-1.0) $ git checkout master
(master) $ git merge [--no-ff] release-1.0
(master) $ git tag -a 1.0

 

같은 내용을 develop 에도 반영해줍니다.

(master) $ git checkout develop
(develop) $ git merge [--no-ff] release-1.0

 

이후 release 브랜치는 삭제해줍니다.

(develop) $ git branch -d release-1.0

 

3) tag -> artifact repository (Optional)

모듈일 경우 sonatype nexus 같은 artifact repository 를 이용해 upload 해줄 필요가 있습니다.

(develop) $ git checkout 1.0
(1.0) $ nexus_upload

tag 로 checkout 된 이후에는 빌드 도구에 설정한 repository 업로드 명령어를 이용하면 됩니다.

 

 

핫픽스 브랜치 (hotfix branch)

hotfix 브랜치는 release 브랜치와 비슷한 flow와 특성을 지닙니다.

다만 한 가지 다른점이 있다면, 계획되지 않았다는 점입니다.

hotfix 를 진행하는 것은 의도치 않은 버그가 발생했다는 이유이기 때문이겠죠.

 

즉시 해당 버그가 수정되고, 배포되어야 할 때 hotfix 브랜치를 사용합니다.

 

라이프 사이클:

(branch off from) master -> hotfix

(merge back into) hotfix-> develop, hotfix-> master

 

 

위 과정은 release 브랜치와 정말 유사합니다.

 

1) 운영버전(master)으로 부터 hotfix 브랜치 만들기

(master) $ checkout -b hotfix-1.0.1

# ... BUG FIXES! and Modify project versioning related

(hotfix-1.0.1) $ git commit -m "Deploy bug fixed version 1.0.1"

 

2) hotfix -> develop, hotfix -> master

(release-1.0) $ git checkout master
(master) $ git merge [--no-ff] hotfix-1.0.1
(master) $ git tag -a 1.0.1

 

같은 내용을 develop 에도 반영해줍니다.

(master) $ git checkout develop
(develop) $ git merge [--no-ff] hotfix-1.0.1

 

이후 hotfix 브랜치는 삭제해줍니다.

(develop) $ git branch -d hotfix-1.0.1

 

 

 

마치며

글은 길어보이지만 정말 어렵지 않은 내용입니다.

좋은 코드와 로직을 작성했다면, 버전관리 또한 전략적으로 진행하여 프로젝트를 아름답게 유지합시다.

 

 

참고문헌

https://nvie.com/posts/a-successful-git-branching-model/


1개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다