
Git에서 여러 사람이 각자 브랜치를 만들어 작업하다 보면, 최종적으로 변경 내용을 하나로 병합(merge) 해야 합니다. 이때 단순히 브랜치를 합치는 것 같지만, 어떤 방식으로 병합하느냐에 따라 Git의 커밋 이력 구조가 달라집니다.
대표적인 병합 방식으로 Fast-Forward Merge, Merge Commit (일반 병합), Squash Merge, Rebase & Merge가 있습니다.

--no--ff옵션을 주지 않은plainmerge가 Fast-Foward Merge입니다.
기준이 되는 베이스 브랜치(base branch)에 이후 추가된 커밋이 없다면, Git은 단순히 베이스 브랜치의 HEAD를 병합할 브랜치의 HEAD로 이동시켜 병합을 완료합니다.
말 그대로 베이스 브랜치의 포인터를 앞으로 "빨리 감기(Fast-Forward)" 하는 것이고, 마치 처음부터 그 새로운 브랜치에서의 커밋들을 베이스 브랜치에서 쌓아온 것처럼 이력이 일직선으로 합쳐집니다.
main 브랜치의 커밋 1과 2 (노란 원) 이후 분기된 feature 브랜치의 커밋 A, B, C(초록 원)가 있습니다. 이 경우 main 브랜치에는 추가 커밋이 없으므로, feature를 병합할 때 별도의 커밋을 만들 필요 없이 main 브랜치의 HEAD를 feature의 마지막 커밋 C로 이동시킵니다. 그 결과 main 브랜치의 이력이 1 → 2 → A → B → C 순으로 선형적으로 연결되며 병합이 완료됩니다.
(Git 명령으로는 git merge feature를 실행하면 Fast-Forward가 가능한 상황에서는 자동으로 이 방식으로 병합됩니다.)
✅ 장점:
❌ 단점:

두 브랜치가 각각 다른 이력을 가지고 있다면, Git은 그 둘을 합치는 새로운 커밋을 생성하여 병합을 수행합니다.
이 새로운 커밋을 merge 커밋이라고 하며, 부모(parent) 커밋을 두 개 갖습니다. 하나는 베이스 브랜치의 마지막 커밋이고 다른 하나는 병합되는 브랜치의 마지막 커밋입니다.
Merge 커밋은 실질적인 코드 변경은 없고 “여기서 두 갈래 이력이 합쳐졌다”는 정보만 담고 있습니다.

노란 원의 1, 2 커밋 이후 main 브랜치에 3, 4, 5 커밋이 이어졌고, 2 커밋 시점에 분기된 feature 브랜치에는 초록 원의 A, B, C 커밋이 있습니다.
이제 두 갈래의 이력을 병합하면, main 브랜치에 새로운 Merge 커밋(분홍색 6) 이 생성됩니다. 이 Merge커밋 6은 부모 커밋을 두 개 갖는데, 하나는 main 쪽의 이전 커밋 5이고 다른 하나는 병합된 feature 브랜치의 마지막 커밋 C입니다.
Merge 커밋 6을 통해 두 브랜치의 변경 사항이 합쳐졌으며, 결과 그래프에서 보듯이 분기됐던 이력이 다시 하나로 합류하게 됩니다.
CLI에서 git merge feature를 했을 때 Fast-Forward가 불가능한 상황이면 자동으로 이렇게 merge 커밋을 만들어 병합합니다. 또한 Fast-Forward가 가능해도 git merge --no-ff 옵션을 주면 강제로 merge 커밋을 남깁니다.
✅ 장점:
--graph 옵션 등으로 시각화하면 브랜치가 분기되었다가 merge 커밋에서 합쳐지는 모습이 드러나기 때문에, 프로젝트의 병합 흐름을 이해하기에 좋습니다.❌ 단점:
merge 커밋은 말 그대로 병합을 위한 추가 커밋이기 때문에, 이러한 커밋들이 많아지면 히스토리가 다소 복잡하고 지저분하게 보일 수 있습니다.
큰 프로젝트에서는 메인 브랜치에 기능을 머지할 때마다 merge 커밋이 쌓여 로그를 깔끔하게 보기가 어려워집니다. Merge 커밋 자체는 코드 변경이 없고 부모 이력에 대한 메타정보만 담고 있으므로, 요약하면 완전한 이력을 보존하는 대신 히스토리가 복잡해집니다.
병합할 브랜치의 모든 커밋을 합쳐서 완전히 새로운 하나의 커밋을 만들어 베이스 브랜치에 추가하고 병합을 완료합니다.
결과적으로 베이스 브랜치에는 병합된 브랜치의 변경사항이 반영되지만, 개별 커밋 기록은 남지 않게 됩니다.
로컬 Git 명령어로는git merge --squash 브랜치명으로 수행하며, 자동으로 커밋까지 만들지 않고 변경 사항만 합친 뒤 사용자가 수동으로 git commit을 실행해 하나의 커밋을 만들게 됩니다.
그래프에서 노란 원의 main 브랜치 커밋 1, 2 이후 분기된 feature 브랜치에 초록 원의 A, B, C 커밋이 있습니다. main 브랜치에는 그 사이 3, 4, 5 커밋이 추가된 상황입니다.
이 feature 브랜치를 Squash & Merge하면, A, B, C의 변화내용을 모두 합친 새로운 커밋 6(분홍색) 이 생성되어 main 브랜치에 추가됩니다. 이때 6은 하나의 부모만 가지며 (main의 이전 커밋 5가 부모), 분기됐던 feature 브랜치의 개별 커밋들은 main의 이력에 남지 않게 됩니다.
결과를 보면 main 브랜치에는 1-5 기존 커밋들 다음에 6 커밋 하나만 올라와 있고, A,B,C 커밋은 사라진 것을 알 수 있습니다. 즉, feature의 모든 변경사항이 6 커밋 하나로 압축되어 병합된 것입니다.
보통 Squash Merge를 하면 커밋 메시지는 해당 브랜치의 PR 제목 등으로 자동 생성하거나, 여러 커밋 메시지를 개행으로 합쳐 편집하게 됩니다.
✅ 장점:
❌ 단점:

보통 기능 브랜치를 최신 상태로 업데이트하거나, 병합 대신 히스토리를 다시 쓰는 방식으로 변경 내용을 가져올 때 사용됩니다.
git rebase를 실행하면 선택한 브랜치의 base(시작 지점) 를 다른 커밋으로 변경한 후, 해당 브랜치의 커밋들을 새로운 기반 위에 차례로 재적용(reapply) 합니다.
예를 들어 feature 브랜치가 main 브랜치의 옛 커밋에서 갈라졌다면, git rebase main을 통해 feature의 기반을 최신 main 브랜치 HEAD로 옮기고 나서 feature의 각 커밋(A, B, C...)을 다시 쌓는 것입니다.
이렇게 rebase가 끝나면 feature 브랜치는 내용은 같지만 이력이 main 브랜치 끝부분에 이어진 상태가 됩니다
그 후 main 브랜치에 feature를 Fast-Forward 방식으로 병합하면 (혹은 GitHub의 “Rebase and merge”를 선택하면) merge 커밋 없이도 두 브랜치의 변경 사항이 통합됩니다.
한마디로 “브랜치를 최신 기반으로 미리 맞춘 다음 합치는” 방법이라고 이해할 수 있습니다.
노란 원의 main 브랜치 커밋 1, 2, 3, 4, 5와, 2에서 분기된 초록 원의 feature 브랜치 커밋 A, B, C가 있습니다.
이 상황에서 feature 브랜치를 main 브랜치의 최신 커밋 5로 Rebase하면, feature 브랜치의 기반이 5로 변경되고 A, B, C 커밋이 그 위로 재배치됩니다.
그런 다음 병합을 수행하면 Fast-Forward로 처리되어, 별도 merge 커밋 없이 main 브랜치의 뒤에 A, B, C 커밋이 직접 연결됩니다.
결과 그래프를 보면 main 브랜치의 5 다음에 feature의 A, B, C가 일렬로 이어져 있으며, 결국 히스토리가 선형으로 합쳐진 것을 알 수 있습니다 (마치 처음부터 A, B, C 작업을 main 브랜치에서 한 것처럼 보입니다).
이 방식이 Rebase라 불리는 것으로, GitHub의 PR 병합 옵션에서도 제공됩니다.
✅ 장점:
❌ 단점: