개발 프로젝트에서 Git은 버전 관리를 위한 기본 도구로 자리 잡았습니다. 하지만 단순히 코드를 저장하는 것을 넘어서, 협업을 효율적으로 이끌어내는 구조를 만드는 것이 더 중요해졌습니다. 그 중심에는 바로 브랜치 전략이 있습니다.
작은 기능 하나를 추가할 때도, 버그를 고칠 때도, 심지어 배포를 준비할 때조차도 브랜치 전략이 잘 정리되어 있지 않다면 팀원 간의 충돌이 발생하거나, 예상치 못한 오류가 배포되는 상황이 생길 수 있습니다. 반대로, 명확한 브랜치 룰은 코드의 흐름을 정리하고, 안정적인 릴리즈를 가능하게 만들어줍니다.
이 글에서는 제가 프로젝트를 진행하면서 실제로 적용했던 Git 브랜치 전략에 대해 소개하고, 어떤 규칙을 정했으며 왜 그런 선택을 했는지에 대한 경험을 공유하려 합니다.
1. Branch Rule
✅ main — 운영 서버 배포용 브랜치
- 최종 릴리스 버전이 관리됩니다.
- release 브랜치에서 충분히 안정화된 코드를 머지해 운영 서버에 배포합니다.
- 이 브랜치의 코드는 항상 배포 가능한 상태여야 합니다.
✅ release — 개발 서버 배포용 브랜치
- develop 브랜치에서 충분한 기능 개발이 이루어진 뒤, 개발 서버에 배포하기 위해 머지됩니다.
- QA, 피드백 반영, 버그 수정 등이 이루어집니다.
✅ develop — 다음 출시 버전 대비 브랜치
- 실질적인 기능 개발이 모이는 중심 브랜치입니다.
- 모든 기능 브랜치(feature)는 여기서 분기되고, 다시 이쪽으로 머지됩니다.
✅ feature — 기능 단위 브랜치
- 기능별로 독립적인 작업을 수행합니다.
- 작업 완료 시 develop 브랜치로 머지됩니다.
📛 feature 브랜치 네이밍 규칙
type/#이슈번호-간략한설명
feat/#312-add-login-api
fix/#317-auth-token-error

위처럼 브랜치명만 봐도 어떤 작업인지 명확하게 파악할 수 있도록 네이밍 규칙을 정해두었습니다.
2. Merge Rule
✅ 새로운 기능 브랜치 -> (Sqush and Merge) -> develop
기능 개발 중에는 수정 테스트, 다시 시도 같은 자잘한 커밋들이 생기기 마련입니다..
Squash and Merge를 사용하면 PR 병합 시 이 모든 커밋을 하나의 커밋으로 합칠 수 있습니다.
따라서 develop 브랜치의 히스토리를 깨끗하게 유지할 수 있어,
새로운 기능 브랜치에서 develop 브랜치로는 Sqush and Merge를 사용하기로 했습니다.
✅ develop-> (Rebase and Merge) -> release
Rebase Merge는 병합 대상 브랜치의 커밋 위에, 작업 브랜치의 커밋들을 그대로 복사해 재배치하는 방식입니다.
따라서, develop 브랜치 내에서 squash를 사용해 여러 커밋을 하나로 합쳐 놓았더라도, rebase를 통해 이 커밋들이 다시 개별 커밋으로 풀려나면서 병합되기 때문에, 세부 작업 내용까지 다시 드러나는 구조로 재정렬됩니다.
이를 통해 하나의 기능이 어떤 단위로 쪼개져 개발되었는지, 어떤 수정이 있었는지를 더욱 정밀하게 추적할 수 있는 히스토리를 만들 수 있다고 생각했습니다. 따라서, 실제로 배포되는 단계인 release 브랜치부터는 Rebase and Merge를 사용하기로 했습니다.
☠️ 문제 발생 ☠️
처음 develop 브랜치의 내용을 release 브랜치에 Rebase Merge 방식으로 병합하는 데 문제없이 성공했습니다.
하지만 이후 진행한 두 번째 Rebase Merge 작업 과정에서는 충돌이 발생했고, 병합이 정상적으로 이루어지지 않았습니다.
두 번째 Rebase Merge 작업이 예상과 달리 충돌을 일으킨 이유를 파악하는 과정에서, 저는 Rebase의 동작 방식에 대한 근본적인 이해가 필요하다는 것을 깨달았습니다.
Rebase Merge는 단순히 기존 커밋을 다른 브랜치 위로 복사해 붙이는 것이 아니다. 기존 커밋과 내용은 같더라도, Rebase는 그 커밋을 완전히 새로운 커밋으로 생성합니다.
즉, 동일한 작업 내용을 담고 있어도, 해시값이 달라지는 "다른 커밋"이 되는 것이었습니다.
이러한 차이 때문에, 이전에 develop 브랜치를 main 브랜치로 rebase 한 이후, 다시 develop 브랜치를 release 브랜치에 rebase 하려 했을 때, Git은 release 브랜치 입장에서 이미 병합된 커밋과 겹치는 부분이 전혀 없는 것처럼 판단했고. 그 결과 충돌이 발생한 것입니다.
✅ develop-> (Merge) -> release
이러한 문제를 겪은 끝에, 저희 팀은 develop 브랜치와 release 브랜치 간의 병합에서는 더 이상 Rebase Merge 방식을 사용하지 않기로 결정했습니다. 대신, 기존의 브랜치 이력을 보존하면서도 안정적인 병합이 가능한 일반 Merge 방식으로 전략을 전환하였습니다.
이러한 선택은 작업 내역의 히스토리를 추적하는 데 일부 제한이 있긴 하지만, 브랜치 간 충돌 가능성을 줄이고 병합 과정에서의 예기치 못한 오류를 방지할 수 있다는 점에서 더욱 효율적인 선택이 될 수 있었습니다.
팀의 협업 상황과 브랜치 전략에 따라, 적절한 병합 방식을 유연하게 선택하는 것이 중요하다는 교훈을 얻을 수 있었습니다.