Git Pull Request 병합 전략
PR 병합 개요
PR 생성 및 병합
Github 과 같은 플랫폼을 통해 개발을 진행할때 보통 메인(Main) 브랜치에서 기능(Feature) 브랜치를 생성한 다음 PR 을 만들게 됩니다. PR 리뷰가 마무리 되고 나서 병합(Merge)를 할 때쯤 되면 메인 브랜치에 다른 분들의 작업이 병합되어 브랜치가 자라난 상태가 되죠. 보통 아래와 같은 상태가 됩니다.
그리고 승인(Approve)를 받고나면 우리에겐 세가지의 선택 옵션이 주어집니다. 어떤 버튼을 누르던 메인 브랜치의 파일 상태 결과는 동일하지만 브랜치가 어떻게 자라나는지에 대해서는 정말 커다란 차이가 있게 됩니다. 다른 말로 표현하면 메인에 저장되는 커밋들이 완전히 다른 형태를 가집니다.
병합 전략에 따른 차이
파일 상태가 동일한데 왜 이런걸 알아야하냐! 라고 할수도 있겠지만 전 포스트에서도 말씀드린 것처럼 Git 에서 하나의 커밋은 변경사항 과 변경시각 정보를 가지게 되는데 각 전략에 따라 이 커밋들이 다르게 구성되기 때문에 크게 두가지 관점에서 변화를 주게 됩니다.
- 충돌(Conflict): 병합 전략에 따라 다른 개발 브랜치에 충돌을 만들 수 있는 경우가 많아질 수 있습니다.
- 예를 들어,
Merge commits
보다는Squash and merge
가 충돌이 발생할 가능성이 높습니다.
- 예를 들어,
- 메인 브랜치의 모양: 병합 전략에 따라 관리의 난이도가 달라집니다.
- 예를 들어,
Squash and merge
전략을 선택하면 불완전 커밋(즉, 리뷰가 안된 코드 상태를 가지는 커밋)을 제거할 수 있습니다.
- 예를 들어,
자세한 내용은 각 병합 전략에 따라 설명드리도록 해볼게요.
Git Merge 전략
Merging commits, 직역하면 기능 브랜치의 커밋들을 메인 브랜치에 병합하는 것입니다. 그림으로 표현하면 아래와 같은 상태가 됩니다.
브랜치를 병합할 때 병합된 상태다! 라는걸 저장하는 커밋을 하나 더 추가합니다. 그래서 딱히 코드 변경사항이 없는 위 그림에서 *
로 표시한 추가 커밋이 생성되죠. 해당 커밋을 지우면? 병합 정보가 날라갑니다. 그래서 브랜치 병합을 잘못했을 때 저 병합 커밋(Merge commit) 을 삭제하는 것으로 복구하기도 한답니다.
Git Merge 방법
PR 에서는 Create a merge commit
을 통해 위 작업을 수행할 수 있는데 명령어로도 가능합니다.
❯ (main) git merge origin/boo-feature
전 포스트에서 merge
설명을 드릴 때 사용했던 커맨드로 흔히 “머지했다” 하면 이 작업을 의미합니다.
Git Merge 장점
- 충돌(Conflict)을 줄일 수 있습니다. 실제 작업들은 고유의 변경사항 과 변경시각 정보를 보존합니다. 고로 해시가 유지됩니다.
Git Merge 단점
- 메인 브랜치에 불완전 커밋이 존재합니다.
- 장애 상황에서 롤백할 커밋을 메인 브랜치에서 찾고 있는데 수 많은 wip 커밋들을 보고 있으면 🔥가 납니다.
- PR은 보통 작업단위로 관리하는데 메인 브랜치에서는 서로 다른 작업의 커밋들이 섞인 순서로 존재하기 때문에 작업단위를 파악하는 것이 불가능해집니다.
Git Squash 전략
Squash merging, 직역하면 기능브랜치의 커밋들을 합쳐서 하나의 커밋으로 메인 브랜치에 병합하는 것입니다. 그림으로 표현하면 아래와 같은 상태가 됩니다.
병합이라고 했지만 기술적으로는(Technically) 병합이 아닙니다.(으잉) 왜냐하면 Git Merge 와 다르게 병합(Merge) 커밋을 남기지 않기 때문이죠. 이게 무슨 차이가 있을까요? 기능 브랜치의 상태가 달라집니다. 무슨 말이냐면 Merge 전략을 수행할 경우 기능 브랜치와 메인 브랜치가 바라보는 커밋이 동일하지만 Squash 전략의 결과 기능 브랜치는 완전히 다른 커밋인 병합전의 커밋을 바라보고 있게 됩니다.
Git Squash 방법
PR 에서는 Squash and merge
을 통해 위 작업을 수행할 수 있는데 명령어로도 가능합니다.
❯ (main) git merge --squash origin/boo-feature
Git Squash 장점
- 메인 브랜치에서 불완전 커밋(즉, 리뷰가 안된 코드 상태를 가지는 커밋)을 제거할 수 있습니다.
- 보통 메인 브랜치의 커멧들은 배포해도 되는 상태로 관리하는데 이를 지킬 수 있습니다.
- “1커밋 - 1PR” 의 관계가 형성되서 작업 관리가 수월합니다.
- 특정 커밋의 변경사항을 하나의 PR 에서 모두 확인할 수 있고 해당 작업에 히스토리가 모여있기 때문에 문제가 발생한 경우 원인 찾기가 쉽습니다.
Git Squash 단점
- 기능 브랜치 커밋의 변경사항과 변경시각 모두가 변하기 때문에 충돌이 발생할 위험이 높습니다.
- 기능 브랜치에서 또다른 기능 브랜치를 생성해서 관리하는 것이 매우 어렵습니다.
Git Rebase 전략
Rebase merging, 직역하면 기능브랜치의 베이스를 메인 브랜치의 최신상태로 변경한 후 기능 브랜치의 커밋들을 쌓아 올립니다. 여기서 main 으로 fast-foward
병합을 하는 것이 Rebase 전략입니다. 그림으로 표현하면 아래와 같은 상태가 됩니다.
이렇게 Rebase 전략으로 기능 브랜치를 메인 브랜치에 병합할 수 있습니다.
Rebase 전략은 메인 브랜치로 병합할 때도 사용할 수 있지만 기능 브랜치의 상태를 관리할 때도 매우 유용합니다. 기능 브랜치에 메인 브랜치의 새로운 작업 내역을 가져올 때 Merge 전략을 사용하는 경우를 많이 보았는데 이럴 경우 최신의 메인 브랜치 커밋보다 이전에 있는 기능 브랜치 커밋들이 존재할 수 있습니다. 이로 인해 Merge 전략을 수행할 때마다 충돌(Conflict)이 발생할 수 있는데 Rebase 를 기능 브랜치에서 수행하시면 이미 발생한 충돌에 대해서는 다시 경험하지 않을 수 있습니다. 기능 브랜치를 메인 브랜치로 Rebase 하면서 기능 브랜치의 커밋들이 메인 브랜치 최신 커밋 이후로 생성을 해주니까요.
Git Rebase 방법
PR 에서는 Rebase and merge
을 통해 위 작업을 수행할 수 있는데 명령어로도 가능합니다.
❯ (boo-feature) git pull --rebase origin main # 먼저 boo-feature 를 main 으로 rebase 합니다.
❯ (main) git pull --ff-only origin boo-feature
Git Rebase 장점
- 하나의 PR 에서 생성된 커밋들을 모으기 때문에 Squash 만큼은 아니지만 메인 브랜치를 작업 단위로 관리할 수 있습니다.
- Fast foward 를 통해 변경사항이 없는 커밋(Merge commit)을 방지합니다.
Git Rebase 단점
- Merge 와 마찬가지로 메인 브랜치에 불완전 커밋이 존재합니다.
- 기능 브랜치 커밋의 변경시각 이 변하기 때문에 충돌이 발생할 위험이 높아집니다.
댓글남기기