Merge 전략과 충돌 해결
PR을 머지하는 세 가지 방식과, 머지 과정에서 생기는 충돌을 해결하고 예방하는 방법을 다룹니다.
Merge 전략 3종 비교
PR 화면에서 초록색 Merge pull request 버튼을 누르면, 사실 GitHub는 이 버튼 하나에 3가지 병합 방식을 숨겨 두고 있습니다. 어떤 걸 고르든 최종 코드 결과물은 똑같지만, 커밋 히스토리 모양이 완전히 달라집니다.
Merge Commit
두 브랜치의 변경 사항을 모두 유지하면서, 병합을 나타내는 새 커밋 하나를 추가하는 방식입니다. 각 브랜치의 과거 커밋이 그대로 남습니다.
- 장점: 히스토리를 전부 보존. 커밋 ID가 안 바뀌어서 다루기 쉬움
- 단점: 브랜치가 많아질수록 히스토리가 지저분해짐
Squash and Merge
브랜치의 모든 커밋을 하나로 압축해서 병합합니다. 3~5개의 자잘한 커밋이 있었다면, 그게 전부 새 커밋 1개로 뭉쳐집니다.
- 장점: 커밋 하나 = PR 하나 = 완성된 기능 하나. 히스토리가 깔끔함
- 단점: 개별 작업 이력이 사라짐. 이미 같은 브랜치에서 여러 명이 작업 중이었다면 커밋 ID가 통째로 바뀌어 혼란이 생길 수 있음 (단, GitHub의 PR 자체 기록은 남아있어서 검색은 가능)
Rebase and Merge
현재 브랜치를 대상 브랜치 위로 **재배치(rebase)**한 뒤 병합합니다. 커밋들이 target 브랜치의 최신 커밋 위로 순서대로 옮겨 붙어서, 히스토리가 선형으로 유지됩니다.
- 장점: 깔끔하고 선형적인 히스토리
- 단점: 관련 커밋 ID가 전부 바뀜. 여러 명이 동시 작업 중이면 복잡한 충돌 유발 가능. 어떤 PR이 어디부터 어디까지였는지 구분이 어려워짐
비교 정리
| 방식 | 히스토리 형태 | 커밋 ID | 추천 상황 |
|---|---|---|---|
| Merge Commit | 브랜치 이력 그대로 + 병합 커밋 | 안 바뀜 | 처음 시작할 때, 규모가 작을 때 |
| Squash and Merge | PR 1개 = 커밋 1개 | 바뀜 | 히스토리를 깔끔히 유지하고 싶을 때 |
| Rebase and Merge | 완전 선형 | 바뀜 | 히스토리 순서가 중요할 때 |
처음에는 Merge Commit으로 시작해보고, 프로젝트가 커져서 관리가 힘들어지면 squash나 rebase로 정리하는 걸 추천합니다. 무엇보다 중요한 건 팀 내에서 방식을 통일하는 것입니다.
Merge 충돌, 해결과 예방
**충돌(Conflict)**은 두 브랜치가 같은 파일의 같은 부분을 서로 다르게 고쳤을 때 발생합니다. Git이 "둘 중 뭘 써야 할지 모르겠다"고 판단해서 사람에게 판단을 넘기는 것이죠. 충돌 부분은 다음과 같은 마커로 표시됩니다.
<<<<<<< HEAD
print("1mo")
=======
print("hello")
>>>>>>> test/branch1해결 방법 두 가지
① GitHub UI의 Resolve conflicts 버튼 버튼을 누르면 4가지 선택지가 생깁니다: 현재 브랜치 내용 쓰기 / 가져오는 브랜치 내용 쓰기 / 둘 다 쓰기 / 직접 수정하기. 해결 후 Mark as resolved → Commit merge 순서로 진행합니다.
② 로컬에서 해결하기 GitHub UI는 IDE 지원이 없어서 복잡한 충돌엔 위험할 수 있습니다. 이럴 땐 로컬에서 직접 해결하는 게 안전합니다.
git checkout test/branch1
git merge main
# 충돌 마커를 직접 열어서 수정
git add .
git commit
git pushVS Code 최신 버전에는 Resolve in Merge Editor 버튼이 있어서, 왼쪽(incoming)/오른쪽(current)/결과(아래)를 한 화면에서 비교하며 수정할 수 있습니다. 편하긴 하지만 본질은 텍스트를 직접 고치는 것과 같습니다.
충돌을 아예 줄이는 방법
- 최신 코드 유지: 개발 기간이 길어질수록 메인 브랜치와의 차이가 벌어집니다. 매일 아침처럼 정기적으로
git merge로 최신 코드를 당겨오는 루틴을 만들어두면 충돌이 크게 줄어듭니다. - 작은 PR 만들기: PR이 작을수록 변경 범위가 좁아 충돌 가능성과 해결 난이도가 함께 줄어듭니다. (다만 소프트웨어 구조가 잘 나뉘어 있어야 가능한 방법입니다.)
- 파일을 작게 쪼개기: 충돌은 파일 단위로 발생합니다. 관계없는 함수들이 한 파일에 몰려 있으면, 서로 다른 브랜치가 파일 끝에 각자 함수를 추가하다가 "의미 없는" 순서 충돌이 생기기 쉽습니다. 파일을 목적별로 쪼개면 이런 충돌 자체가 줄어듭니다.
- 동료와 커뮤니케이션하기: 기술력만큼 중요한 게 소통입니다. 서로 밀접하지 않은 기능부터 우선순위를 나눠 작업하면 자연스럽게 충돌이 줄어듭니다.
정리
| 개념 | 한 줄 요약 |
|---|---|
| Merge Commit | 두 브랜치 이력을 그대로 보존하며 병합 커밋 하나 추가 |
| Squash and Merge | 여러 커밋을 하나로 압축해서 병합, 히스토리가 깔끔해짐 |
| Rebase and Merge | 커밋을 target 위로 재배치해 선형 히스토리로 병합 |
| Merge 충돌 | 같은 파일의 같은 부분을 다르게 고쳤을 때 발생, 마커를 직접 수정해서 해결 |
| 충돌 최소화 | 최신 코드 자주 당겨오기 + 작은 PR/파일 + 활발한 커뮤니케이션 |
출처: Codyssey-B1/B2-2
