Git 병합 전략은 명령어 취향의 문제가 아닙니다. 같은 코드 변경이라도 merge, fast-forward, squash, rebase 중 무엇을 선택하느냐에 따라 팀이 나중에 읽게 되는 히스토리가 달라집니다. 파일 내용은 같아도, 장애를 추적하거나 특정 기능이 들어간 시점을 찾을 때의 경험은 전혀 달라질 수 있습니다.
병합 전략을 고를 때 먼저 볼 것은 명령어의 깔끔함이 아니었습니다. 장애나 회귀가 생겼을 때 main 히스토리에서 변경 묶음을 다시 추적할 수 있는지, PR의 의도가 커밋 로그에 남는지, 공유 브랜치의 기준점을 누가 다시 쓸 수 있는지가 더 중요했습니다. 여기서는 merge, rebase, squash를 명령어 비교가 아니라 팀이 어떤 기록을 남기고 어떤 디버깅 비용을 감수할 것인지의 문제로 정리합니다.
병합 전략은 히스토리 정책입니다
Git에서 병합 전략을 고를 때 자주 빠지는 함정은 최종 파일만 보는 것입니다. 실제로 merge, squash, rebase 모두 최종 결과물을 같게 만들 수 있습니다. 하지만 커밋 그래프에 남는 정보는 다릅니다.

팀이 나중에 히스토리를 읽는 이유는 보통 세 가지입니다.
- 어떤 기능이 언제 들어갔는지 찾기 위해
- 장애나 회귀가 어느 변경에서 시작됐는지 좁히기 위해
- 특정 PR 또는 기능 묶음을 되돌리기 위해
따라서 좋은 병합 전략은 히스토리를 무조건 짧게 만드는 전략이 아닙니다. 나중에 문제를 추적할 수 있는 단서가 남는 전략입니다.
일반 Merge는 분기와 합류를 그대로 남깁니다

일반적인 merge는 두 브랜치가 분기된 뒤 다시 합쳐졌다는 사실을 merge commit으로 남깁니다.
git checkout main
git merge feature장점은 기능 브랜치의 흐름이 보존된다는 점입니다. 어떤 브랜치가 언제 main에 합쳐졌는지, 그 브랜치 안에 어떤 커밋들이 있었는지 확인할 수 있습니다. 장기간 작업한 기능이나 릴리즈 브랜치처럼 변경 묶음의 경계가 중요한 경우 유리합니다.
단점도 분명합니다. 작은 PR까지 모두 merge commit으로 남기면 로그가 빠르게 복잡해집니다. 특히 자주 main을 merge한 브랜치라면 커밋 그래프가 불필요하게 얽힐 수 있습니다.
| 좋은 경우 | 주의할 경우 |
|---|---|
| 긴 기능 브랜치, 릴리즈 브랜치, 변경 묶음 추적이 중요한 PR | 작은 수정 PR, 커밋 단위가 정리되지 않은 브랜치 |
Fast-Forward는 가장 단순하지만 경계가 사라집니다

Fast-forward merge는 대상 브랜치가 feature 브랜치의 조상일 때, 별도 merge commit 없이 포인터만 앞으로 이동시키는 방식입니다.
git checkout main
git merge --ff feature히스토리는 깔끔하게 직선으로 남습니다. 하지만 브랜치가 따로 존재했다는 기록은 약해집니다. 작은 변경을 빠르게 넣을 때는 좋지만, PR 단위의 의미를 히스토리에 남기고 싶다면 부족할 수 있습니다.
git merge --no-ff feature--no-ff를 사용하면 fast-forward가 가능한 상황에서도 merge commit을 남길 수 있습니다. 이 선택은 “코드가 어떻게 합쳐지는가”보다 “브랜치 경계를 기록으로 남길 것인가”의 문제입니다.
Squash Merge는 PR을 하나의 결과 커밋으로 압축합니다

Squash merge는 feature 브랜치의 여러 커밋을 하나의 커밋으로 합쳐 main에 반영합니다.
git checkout main
git merge --squash feature
git commit -m "Add user profile update API"작은 PR이나 단일 목적 변경에서는 squash가 유리합니다. 리뷰 중 생긴 “fix typo”, “review 반영”, “테스트 수정” 같은 중간 커밋을 main에 그대로 남기지 않아도 되기 때문입니다.
하지만 squash는 정보를 버립니다. feature 브랜치 안에서 어떤 실험을 했고, 어떤 중간 결정을 거쳤는지는 main 히스토리에서 사라집니다. 따라서 squash를 기본 전략으로 쓴다면 PR 제목과 본문, 최종 커밋 메시지가 더 중요해집니다.
| 남는 것 | 사라지는 것 |
|---|---|
| PR 하나에 대응되는 결과 커밋 | 브랜치 안의 세부 커밋 흐름 |
| 깔끔한 main 히스토리 | 중간 의사결정과 실험 기록 |
Rebase는 개인 브랜치를 정리하는 도구에 가깝습니다

Rebase는 내 브랜치의 커밋들을 다른 브랜치의 최신 커밋 위로 다시 올립니다.
git checkout feature
git rebase main이 방식은 개인 브랜치를 최신 main 위에 정리할 때 유용합니다. merge commit 없이 선형 히스토리를 만들 수 있고, main 변경과의 충돌을 PR 전에 미리 확인할 수 있습니다.
문제는 공유된 커밋을 rebase할 때 생깁니다. rebase는 기존 커밋을 그대로 이동시키는 것이 아니라 새로운 커밋 해시를 만듭니다. 이미 다른 사람이 기준으로 삼은 커밋을 다시 쓰면, 코드 충돌보다 더 복잡한 히스토리 충돌이 생길 수 있습니다.
git push --force-with-lease강제 push가 필요한 상황이라면 먼저 브랜치가 개인 브랜치인지 확인해야 합니다. 공유 브랜치에서는 --force-with-lease조차도 팀 합의 없이 사용하지 않는 편이 안전합니다.
전략별 비용은 서로 다릅니다
병합 전략의 차이는 결국 비용의 위치입니다.
| 전략 | 장점 | 비용 | 권장 상황 |
|---|---|---|---|
| Merge commit | 분기와 합류 기록 보존 | 그래프가 복잡해질 수 있음 | 긴 기능, 릴리즈, 추적이 중요한 변경 |
| Fast-forward | 가장 단순한 선형 히스토리 | 브랜치 경계가 약해짐 | 작은 개인 변경, 경계 기록이 중요하지 않은 경우 |
| Squash merge | PR 단위로 깔끔한 결과 커밋 | 중간 커밋 맥락이 사라짐 | 작은 단일 목적 PR |
| Rebase | 개인 브랜치 히스토리 정리 | 공유 커밋 재작성 위험 | push 전 개인 브랜치 정리 |
어떤 전략이 항상 우월한 것은 아닙니다. 팀이 어떤 정보를 main 히스토리에 남기고 싶은지, 충돌 해결 비용을 언제 지불할지에 따라 선택이 달라집니다.
브랜치 소유권을 먼저 나눠야 합니다
병합 전략보다 먼저 정해야 할 것은 브랜치의 소유권입니다. 브랜치가 개인 작업용인지, 이미 공유된 기준점인지에 따라 허용할 수 있는 명령어가 달라집니다.
| 브랜치 종류 | 허용하기 쉬운 전략 | 주의할 점 |
|---|---|---|
| 개인 작업 브랜치 | rebase, squash, amend | 원격 공유 전까지 안전 |
| PR이 열린 브랜치 | merge 또는 제한적 rebase | 리뷰 중 커밋 재작성은 리뷰 맥락을 끊을 수 있음 |
| 여러 명이 작업하는 공유 브랜치 | merge | force push 금지 |
| main/release | PR 기반 merge 정책 | 직접 push 금지, CI 통과 필요 |
이 기준 없이 “rebase가 깔끔하다” 또는 “merge가 안전하다”로만 말하면 팀 안에서 같은 충돌이 반복됩니다. 브랜치가 누구의 기준점인지 먼저 정해야 합니다.
충돌 해결은 늦게 할수록 비싸집니다
충돌은 단순히 같은 줄을 수정해서 생기는 문제가 아닙니다. 같은 파일의 책임을 서로 다르게 이해했을 때도 생깁니다. Git은 어떤 줄이 충돌했는지는 알려주지만, 어떤 설계가 맞는지는 알려주지 않습니다.
그래서 충돌 비용을 줄이는 가장 좋은 방법은 병합 전략을 바꾸는 것이 아니라, 브랜치 수명과 PR 크기를 줄이는 것입니다.
- 오래 열린 브랜치는 main과 멀어집니다.
- 큰 PR은 충돌 지점을 이해하기 어렵습니다.
- 커밋 메시지가 부실하면 충돌 해결자가 변경 의도를 되살리기 어렵습니다.
- 리뷰 반영 커밋이 너무 많으면 squash가 필요해지고, squash가 많아지면 PR 본문 품질이 중요해집니다.
커밋 메시지는 리뷰어를 위한 장식이 아니라 미래의 충돌 해결자를 위한 단서입니다. “수정”, “반영”, “작업” 같은 메시지는 충돌 상황에서 거의 도움이 되지 않습니다.
팀 규칙은 단순해야 합니다
실제로 적용할 수 있는 규칙은 복잡할 필요가 없습니다. 예외가 생겼을 때도 팀원이 같은 판단을 할 수 있어야 합니다.
Squash merge를 기본으로 쓴다면 PR 본문과 최종 커밋 메시지가 변경 맥락을 대신해야 합니다. Merge commit을 유지한다면 PR 단위의 경계가 히스토리에 남으므로 PR 제목과 merge commit 메시지가 중요해집니다. 어떤 전략이든 기록을 어디에 남길지 정해야 합니다.
규칙은 저장소 설정으로 고정해야 합니다
병합 전략을 문서로만 정해두면 시간이 지나면서 예외가 늘어납니다. 특히 급한 배포, 작은 수정, 리뷰 지연 같은 상황이 생기면 팀원마다 다른 판단을 할 수 있습니다. 그래서 팀 규칙은 가능하면 저장소 설정으로도 고정하는 편이 좋습니다.
| 정책 | 설정으로 막을 수 있는 실수 |
|---|---|
| main 직접 push 금지 | 리뷰와 CI를 거치지 않은 변경 유입 |
| required checks | 테스트 실패 상태의 병합 |
| allowed merge methods 제한 | 팀이 합의하지 않은 squash, merge commit, rebase merge 혼용 |
| force push 제한 | 공유 브랜치 기준점 재작성 |
| PR template | squash 후 사라질 변경 맥락 누락 |
정책을 설정으로 고정한다는 것은 개발자를 믿지 않는다는 뜻이 아닙니다. 반복해서 판단하지 않아도 되는 일을 도구가 대신 지키게 만드는 것에 가깝습니다. 팀이 논의해야 할 것은 “이번에는 어떤 버튼을 누를까”가 아니라, 예외가 필요한 변경인지와 그 예외를 히스토리에 어떻게 남길지입니다.
참고한 자료
팀에 남겨야 할 기준
병합 전략을 고를 때 예쁜 히스토리부터 보지는 않았습니다. 장애나 회귀가 생겼을 때 누가, 언제, 어떤 의도로 바꿨는지 다시 읽을 수 있는 기록이 남는지를 먼저 봤습니다. 히스토리는 코드 리뷰가 끝난 뒤에도 남는 디버깅 표면이기 때문에, 팀이 어떤 정보를 버리고 어떤 정보를 남길지 먼저 정해야 합니다.
팀에서 병합 방식을 정할 때 확인한 기준은 다음과 같습니다.
- merge commit은 브랜치 경계와 합류 시점을 보존합니다.
- fast-forward는 단순하지만 PR 또는 브랜치 경계가 약해집니다.
- squash merge는 PR 하나를 결과 커밋으로 압축하지만 중간 맥락을 버립니다.
- rebase는 개인 브랜치 정리에 좋지만 공유 커밋을 다시 쓰면 위험합니다.
- 병합 전략은 명령어 선택보다 브랜치 소유권과 히스토리 정책의 문제입니다.
팀의 병합 전략은 기록을 어디까지 남길지에 대한 운영 정책입니다. 히스토리를 짧게 만들 것인지, 변경 묶음의 경계를 남길 것인지, 중간 커밋의 맥락을 보존할 것인지부터 정해야 합니다. 그리고 그 합의는 문서에만 두면 오래가지 않습니다. 브랜치 보호, 허용된 병합 방식, rebase 허용 범위를 저장소 설정으로 맞춰 두어야 같은 실수를 반복하지 않습니다.