브랜치 전략... 머지 전략.... 나는 먼지
브랜치 전략과 머지 전략에 대해 알아봤다. (이제서야)

지난주 금요일, 회사에서 브랜칭 전략에 대해 회의를 진행했는데 내가 생각하고 갔던 내용에 비해 더 깊이 있는 논의들이 진행이 되어서 팀원분들께서 말씀하시는 것들을 들으며 몰랐던 것들에 대해 빠르게 공부를 해야겠다는 생각이 들었다. 안타깝게도 그 전 날 브랜치를 오염시키는 사고를 치기도 했고 ㅠ_ㅠ 흑흑.. 죽어... 사고를 또 칠 수도 없으니! 그리고 또 모르는 걸 듣게 되었는데 그냥 지나치면 안되니! 하나 하나 찾아보기도 하고 직접 연습하며 그래프가 그려지는 것들을 익혀보는 시간을 가져봤다.
🌿 브랜치 전략
1️⃣ Git Flow

Main Branch , Develop Branch , Supporting Branch 로 구분해서 관리하는 방법으로 중심 브랜치는 Main 과 Develop 이다. 중심이 된다는 것은 즉, 개발 전반에 걸쳐 계속 유지되는 브랜치라는 의미이다. 여기서 Supporting Branch 는 다시 Feature Branch , Release Branch , Hotfix Branch 로 나뉘는데, 각 브랜치들은 필요할 때마다 생성하면 되고, 그 역할이 끝나면 삭제한다. 병렬적인 업무 진행을 가능하게 하는 친구들이다.
Main Branch✅Develop Branch✅Supporting BranchFeature BranchRelease BranchHotfix Branch
Main Branch
출시 가능한 프로덕션 코드를 모아두는 브랜치
프로젝트 시작 시 생성 > 개발 프로세스 전반에 걸쳐 유지
배포된 각 버전을
태그를 이용해 표시
Develop Branch
- 다음 버전 개발을 위한 코드를 모아두는 브랜치 > 개발이 완료되면,
Main으로 머지
Feature Branch
역할 : 하나의 기능을 개발하기 위한 브랜치
Develop에서 생성 > 기능 개발 후 다시Develop으로 머지머지 시 주의할 점
Fast-Forward로 머지 X >Merge Commit을 생성해 머지 👉🏻 이렇게 해야 히스토리가 특정 기능 단위로 묶임
네이밍 :
feature/branch-name
Release Branch
역할 : 소프트웨어 배포를 준비하기 위한 브랜치
Develop에서 생성 > 버전 이름 등의 데이터를 수정하거나 배포 전 사소한 버그 수정을 위해 사용배포 준비 완료 시
Main과Develop모두에 머지Main에는 태그를 이용해 버전을 표시
네이밍 :
release/v1.1
Hotfix Branch
이미 배포된 버전에 문제가 발생하면 이 브랜치로 문제 해결
Main에서 생성 > 문제 해결이 되면Main과Develop모두에 머지네이밍 :
hotfix/v1.0.1
2️⃣ Github Flow

Github Flow 는 Git Flow 에 비해 간단한 구조로 Github 환경에서 사용하기 적합한 브랜치 전략으로 자동화를 적극 활용한다. 흐름이 꽤 단순한 편이며, 그만큼 룰도 단순하다. Master 가 그 역할만 정확하게 유지한다면 나머지 브랜치들엔 관여를 하지 않는다. 되도록이면 pull request 기능을 사용하자.
Main Branch
항상 stable한 상태를 유지해야함
Main은 언제 배포하던지 간에, 그리고 언제든 브랜치를 새로 생성해도 문제가 없어야함Main의 모든 커밋은 빌드가 되고, 테스트를 통과해야 함 *Github Flow 가 강제하는 유일한 사항
Topic branch
새로운 기능을 개발할 때
Topic Branch를Main으로부터 생성Git Flow 의 Feature 브랜치와 동일한 역할
별도로 Hotfix 브랜치를 관리하지 않고, 버그 수정도 Topic 브랜치에서 진행
네이밍 > 기능을 설명하는 명확한 이름
user-content-cache-keyredis2-transition
Topic 브랜치의 커밋은 기능이 완성되지 않았더라도 꾸준히 Push
- 꾸준히 Push 함으로써 구성원 모두가 끊임없이 커뮤니케이션
PR 을 통해서 개발된 것들에 대해 코드리뷰를 하고 Approve >
Main에Topic을 머지- 자동화된 CI 빌드를 통과해야 머지 가능
3️⃣ GitLab Flow

Github flow는 너무 간단하다보니 규모가 큰 서비스에는 그 적합도가 떨어진다. 그래서 이것의 단순함을 이용하면서 체계를 갖추기위해 나온 것이 gitLab Flow 라고 한다. pre-production 은 테스트를 담당하는 브랜치이며, production 은 유저가 사용하는 제품이 존배하는 브랜치다.
Master
Git Flow 의
Develop브랜치와 동일 > 개발 단계의 코드가 있는 브랜치Master는Feature브랜치에서 병합된 기능에 대해 테스트를 진행전체적인 테스트가 진행되어 보장이 되었다면
production브랜치로 머지됨Staging단계를 원한다면pre-production브랜치로 머지를 진행
Feature
특정 기능 구현을 위해 생성되는 시작 브랜치
master에서 분기되고 머지됨기능 구현이 마무리되면
master로 PR > 머지 후에는 삭제
Production
Git Flow 의
Master브랜치와 동일테스트가 끝난 기능에 대해 배포를 하기위한 브랜치
Pre-production
Master>Production브랜치 사이에pre-production브랜치를 둬서 변경사항을 바로Production에 배포X- 테스트 서버에 배포해 통합 테스트를 진행하거나 시간을 두고 반영하는 브랜치
🤔 그래서 어떤 전략을 사용하면 좋을까?
는 팀의 상황에 따라 다를 것이라 큰 개념만 이해하고 있으면 얼마든지 응용은 가능할 것 같다. 이전 팀에서 가장 힘들었던 걸 생각해보니 배포 직전에 특정 피쳐가 빠져야하는 경우에 그 피쳐에 대한 분리가 쉽지가 않아 매번 애를 먹었던 기억이 나는데, 이런 부분에 있어서 어떻게 정리를 해두면 편해질 수 있을지 한번 고민을 해봐야겠다.
그리고 이제.. 머지 전략에 대해 공부를 해봤는데, 참..ㅋㅋㅋㅋ 진짜 생각없이 하고 있었다는 생각이 들며 부끄러웠다. 지금이라도 공부하고 연습 했으니 그래도 다행이 아닐까!!!!!!!!
Merge
일반적으로 많이 사용되는 병합이며, 커밋 이력을 모두 남길 때 사용한다. 머지된 브랜치가 삭제되어서 사라진다고 하더라도, 그 history 는 유지되기 때문에 어떤 브랜치에서 머지가 되었는지에 대한 파악이 가능하다는 장점이 있다. 반면에 브랜치가 너무 많이 나눠져있는 경우나 커밋이 상당히 많은 경우에는 가독성이 떨어진다.(굉장히 공감)
$ git checkout main
$ git merge feature/branch
Merge 의 경우, Fast-Forward 와 머지 커밋을 남기는 것이 있었는데, 각각이 어떤 차이가 있는지 살펴보자.
1️⃣ Merge (Fast-Forward)

Fast-Forward Merge 에 대해 알아보자. 설명보다는 그림이 최고라 피그마로 열심히 그려봤다.
위 그림을 보며 순서대로 나열해보면,
main브랜치에서test브랜치가 나옴test브랜치에서 3번의 커밋을 하며 업무를 진행 *그 동안main브랜치의 작업은 따로 Xmain에서test를 머지 >test의 변경 이력을 그대로main으로 가져옴
기존 베이스 브랜치에서 변경된 것이 없기 때문에 모든 커밋들은 하나의 연장선 안에서 나열된다. 실제로 그래프도 그렇게 그려질까?
- Before Merge

- After Merge

그렇다. 확실히 변경점이 겹치지 않다보니 순서대로 진행되듯 하나의 선에서 모두 나열이 되고있다. 다만 이렇게 되면 어떤 브랜치가 언제 머지되었는지 확인이 어려울 수 있겠다.
2️⃣ Merge (Recursive)

이번엔 Recursive Merge 로 가장 많이 사용하는 일반적인 머지 방식이다. 지금껏 개발을 하며 브랜치를 따서 작업을 하는데 main 이 변경되지 않는 것은 개인 프로젝트를 할 때를 제외하고는 없었다. 그래서 매전 머지를 하고 나면 머지 커밋을 남기게 되었었는데, 그게 바로 이 방법이라 생각하면 좋겠다.
위 그림을 보며 순서대로 나열해보면,
main브랜치에서test브랜치가 나옴test브랜치에서 작업을 하는main에서도 계속해서 변경이 일어남main에서test를 머지 > (충돌이 있다면 해결하고) Merge Commit 생성
Fast-Forward Merge가 가능한 상태에서 git merge 명령에 --no-ff 옵션을 주면 강제로 Merge Commit을 생성하게 할 수 도 있기는 하다.
- Before Merge

- After Merge

Fast-Forward 와는 다르게 오른쪽으로 집 나갔던 브랜치가 다시 메인 브랜치로 들어가는 모양을 볼 수 있다. 곁가지 브랜치들이 많아질 수록 점점 뚱뚱해지겠지..
Squash & Merge - Rebase & Merge
그리고 이 녀석들.. 머지 전략을 짜며 어떤 부분에서 리베이스를 하면 좋을지, 아니면 전부 Squash & Merge 로만 가면 좋을지 이야기를 나눴었는데 리베이스는 들어보기만 하고 해본적이 없어서 대화에 함께할 수가 없었다........ 죄송함니다.ㅁㄴ.ㄹ....ㅎ긓ㄱ..ㄱㅁ흐... 그래서... 알아봤지... 다음엔 꼭..
1️⃣ Squash & Merge

Squash 는 여러개의 커밋을 하나의 커밋으로 합치는 것을 의미한다. 즉, Squash & Merge는 병합할 브랜치의 모든 커밋을 하나의 커밋으로 Squash한 새로운 커밋을 Base 브랜치에 추가하는 방식으로 병합하는 것이다. 다만, Squash를 하게 되면 모든 커밋 이력이 하나의 커밋으로 합쳐지며 사라진다는 점을 주의해야함!
위 그림을 보며 순서대로 나열해보면,
main브랜치에서test브랜치가 나옴test브랜치에서 작업을 하는main에서도 계속해서 변경이 일어남main에서test를 머지 > (충돌이 있다면 해결하고) Merge Commit 생성
- Before Merge

- Squash & Merge
# Squash & Merge
git checkout main
git merge --squash test/squash-merge
git commit -m "squash & merge"
- After Merge

그냥 머지했을 때와 그래프를 비교해보면, main 브랜치만 보이게끔 설정했을 때는 아래와 같이 나오고 각각의 차이를 확인할 수 있다.
- Merge (Recursive)

- Squash & Merge

2️⃣ Rebase & Merge

그리고 이 놈.. 제일 이해가 안갔던 녀석.. 내가 이해력이 부족해서일지도..ㅋㅋㅋㅋㅋㅋㅋ Rebase 는 Base 를 다시 설정한다는 의미이다. 즉 Main 을 베이스로 생성했던 브랜치가 있다면 git rebase 명령어로 사용해서 그 베이스 브랜치 자체를 다른 곳으로 설정한다는 것이다.
이 때, 리베이스가 진행되면 진행했던 커밋들은 베이스로 설정한 브랜치의 마지막 커밋 뒤로 붙게 된다. 다만 베이스가 변경되었기 때문에 Commit Hash 또한 변경된다. (Force Push를 하는 경우가 생길 수 있음 주의!)
위 그림을 보며 순서대로 나열해보면,
main브랜치에서test브랜치가 나옴test브랜치에서 작업을 하는main에서도 계속해서 변경이 일어남test는 1번 커밋이 있던 당시를 베이스로 한 상태 > 가장 최신의main브랜치로 리베이스 진행test에서 작업된 2번, 4번 커밋이 리베이스가 진행되며main의 5번 커밋 뒤로 이동이동한 커밋들은 복사된 것으로 Hash 가 변경되어있음
실제 작업된 그래프를 보면,
- Before Rebase : #1 > #2 > #3 > #4

- Rebase
$ git checkout rebase/test01
$ git rebase main
$ git checkout main
$ git merge rebase/test01
After Rebase : #1 > #3 > #2 > #4
- #2, #4 커밋의 경우 Hash 도 변경된 것을 확인할 수 있음

지금까지 다뤘던 케이스는 컨플릭이 일어나지 않았을 경우인데, 그렇다면 리베이스를 하면서 컨플릭이 생기는 경우는 어떻게 될까?

위 그림을 보며 순서대로 나열해보면,
main브랜치에서test브랜치가 나옴test브랜치에서 작업을 하는main에서도 계속해서 변경이 일어남- (조건) 이 과정에서 충돌이 일어나게끔 작업이 되어버림
test를 가장 최신의main브랜치로 리베이스 진행리베이스 과정에서 충돌 해결
충돌 해결 후 Commit
충돌 해결 과정에서 들어갔던 커밋이 5번 커밋 뒤로 붙음
실제로도 저렇게 되는지 직접 확인을 해보면,
- Before Rebase

- Rebase 진행
$ git rebase main
- Rebase > conflict 해결 (1/2) - 기존 베이스 브랜치를 따라간 경우 (변화 X)

$ git add .
$ git rebase --continue
- Rebase > conflict 해결 (2/2) - 기존 베이스 브랜치와 다른 변경점으로 해결한 경우

$ git add .
$ git commit -m "merge - if change base branch's work"
$ git rebase --continue
- After Rebase

두 개 뿐인 컨플릭임에도 상당히 귀찮은 과정이었다. 다만 모든 변경점들을 하나하나 확인할 수 있는 장점은 있는 것 같기도 하다. 또한 리베이스를 하게 되면 깃 그래프 자체가 한 줄 서기를 해서 훨씬 가독성이 좋은 것 같다. 어떤 브랜치가 흘러들어갔는지에 대해 추적하는게 조금 어려울 것 같다는 걱정이 있지만서도..!
리베이스는 많이 해보질 않아서 감이 잘 안왔었는데, 어제 퇴근하고 오늘까지 계속 연습하면서 감을 잡아보니 조금 그림이 그려지는 것 같기도 하다. 실수하지 않도록 조심하긴 해야겠다.
[메모] Git 기본 자주쓰는 명령어
# 저장소 만들기
git init
# 기존 저장소 복제
git clone
# EXAMPLE
git clone https://github.com/{주소}
# 특이사항이 있는 파일의 상태를 알려주기
git status
# 상태만 보는게 아닌 변경 내용까지 확인
git diff
# stage 되어 있으나 아직 commit 되지 않은 변경 내용 확인
git diff --staged
# 새로운 파일 찾기 + Modified 상태 파일을 Staged 로 올림
git add
# 변경된 파일 commit
git commit
git commit -m "text.."
$ git add .
$ git status
$ git commit -m "fix. something"
# commit 덮어쓰기
git commit --amend
$ git commit -m "initial commit"
$ git add forgotten_file
$ git commit --amend
# commit 로그 확인
git log
# 한 줄 그래프 형태로 commit history 확인
git log --oneline --graph
# stage 된 파일을 unstaged 상태로 변경
git reset
# 저장소에 commit 반영
git push
# 저장소에 commit 가져오기
git pull
마무리

출근 3주차... 머지하다 사고치고 회의 때 제대로 이해도 못해서 잠시 우울했는데 흑흐그ㅁㄴㅇㄹ 이렇게라도 시간내서 몰랐던 것들 채워 넣으니 다행이다. 물론 이번에 공부한 내용은 기본 of 기본적인 내용이다 보니 조금씩 더 살을 붙여야할 것 같긴하다. 많이 경험하고, 많이 알아보고 넓혀나가야겄다. 실수와 실패와 부끄러움은 나의 양분. 하지만 반복은 업따. 간바레.. 트루쟝..
![[월간 이트루] 3월의 회고.](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1711895194426%2Ff6a22b40-ffd3-4b11-a25b-e1b040b11853.png&w=3840&q=75)
![[월간 이트루] 2월의 회고.](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1709129901980%2F5a2af3c5-8f6e-4f07-9c4f-1b43bef27ae9.png&w=3840&q=75)

![[월간 이트루] 1월의 회고.](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1706708547437%2F51af577d-21f9-4256-8939-95c577a58abc.jpeg&w=3840&q=75)