[Codeit Sprint]Weekly Paper 2-2 Git branch 병합 방법

DreamPaste·2025년 4월 12일

Weekly Paper

목록 보기
4/8
post-thumbnail

🔄 Git branch 병합이란?

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

1. Fast-Foward Merge

--no--ff 옵션을 주지 않은 plain merge가 Fast-Foward Merge입니다.

🧭 개념

Fast-Forward Merge는 새로운 merge 커밋을 만들지 않고 브랜치를 병합하는 방법입니다.

기준이 되는 베이스 브랜치(base branch)에 이후 추가된 커밋이 없다면, Git은 단순히 베이스 브랜치의 HEAD를 병합할 브랜치의 HEAD로 이동시켜 병합을 완료합니다.
말 그대로 베이스 브랜치의 포인터를 앞으로 "빨리 감기(Fast-Forward)" 하는 것이고, 마치 처음부터 그 새로운 브랜치에서의 커밋들을 베이스 브랜치에서 쌓아온 것처럼 이력이 일직선으로 합쳐집니다.

📑 Fast-Foward 병합 예시

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가 가능한 상황에서는 자동으로 이 방식으로 병합됩니다.)

✅ Fast-Foward 병합의 장단점

✅ 장점:

  • Fast-Forward 병합은 불필요한 병합 커밋 없이 이력이 합쳐지므로 커밋 히스토리가 깔끔하게 일직선으로 관리됩니다.
  • 브랜치의 모든 커밋이 그대로 보존되어 하나하나의 변경 이력도 놓치지 않습니다.
  • 별도의 “Merge” 커밋이 안 생기기 때문에 커밋 기록에 군더더기가 없고, 작업 내용을 시간순으로 파악하기가 수월합니다.

❌ 단점:

  • Fast-Forward는 베이스 브랜치에 새로운 커밋이 없을 때에만 가능한 제한된 시나리오입니다.
  • 여러 개발자가 동시에 작업하는 프로젝트라면 베이스 브랜치가 뒤쳐져 있는 경우가 드물어서 실제로는 자동 Fast-Forward 병합이 일어나기 어렵습니다.
  • 또한 병합 전후로 커밋 그래프 구조가 변하지 않기 때문에, 어느 시점에 어떤 브랜치의 작업이 합쳐졌는지 추후에 추적하기 어렵다는 단점이 있습니다. 나중에 로그를 볼 때 누가 어떤 토픽(branch)을 병합했는지 알기가 힘듭니다.

Merge Commit (일반 머지, 3-way Merge)

🧭 개념

Merge Commit을 만드는 병합은 Git의 기본 병합 방식으로, 세 갈래 병합(3-way merge)이라고도 부릅니다.

두 브랜치가 각각 다른 이력을 가지고 있다면, Git은 그 둘을 합치는 새로운 커밋을 생성하여 병합을 수행합니다.
이 새로운 커밋을 merge 커밋이라고 하며, 부모(parent) 커밋을 두 개 갖습니다. 하나는 베이스 브랜치의 마지막 커밋이고 다른 하나는 병합되는 브랜치의 마지막 커밋입니다.

Merge 커밋은 실질적인 코드 변경은 없고 “여기서 두 갈래 이력이 합쳐졌다”는 정보만 담고 있습니다.

📑 3-way 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 커밋을 남깁니다.

✅ 3-way Merge 병합의 장단점

✅ 장점:

  • 모든 커밋 이력이 보존된다는 것이 merge 커밋 방식의 가장 큰 장점입니다. 병합된 브랜치의 개별 커밋들도 그대로 남기 때문에 기록의 세분화(granularity)가 손실되지 않습니다.
  • 병합 커밋이 “이 지점에서 브랜치가 합쳐졌다”는 것을 명시적으로 보여주므로, 나중에 히스토리를 볼 때 어떤 브랜치의 작업이 언제 합쳐졌는지 추적하기 쉽습니다.
  • 커밋 그래프를 --graph 옵션 등으로 시각화하면 브랜치가 분기되었다가 merge 커밋에서 합쳐지는 모습이 드러나기 때문에, 프로젝트의 병합 흐름을 이해하기에 좋습니다.

❌ 단점:

  • merge 커밋은 말 그대로 병합을 위한 추가 커밋이기 때문에, 이러한 커밋들이 많아지면 히스토리가 다소 복잡하고 지저분하게 보일 수 있습니다.

  • 큰 프로젝트에서는 메인 브랜치에 기능을 머지할 때마다 merge 커밋이 쌓여 로그를 깔끔하게 보기가 어려워집니다. Merge 커밋 자체는 코드 변경이 없고 부모 이력에 대한 메타정보만 담고 있으므로, 요약하면 완전한 이력을 보존하는 대신 히스토리가 복잡해집니다.


3. Squash Merge (스쿼시 머지)

🧭 개념

Squash Merge는 말 그대로 여러 커밋을 한 개의 커밋으로 뭉쳐(Squash) 병합하는 방법입니다.

병합할 브랜치의 모든 커밋을 합쳐서 완전히 새로운 하나의 커밋을 만들어 베이스 브랜치에 추가하고 병합을 완료합니다.
결과적으로 베이스 브랜치에는 병합된 브랜치의 변경사항이 반영되지만, 개별 커밋 기록은 남지 않게 됩니다.
로컬 Git 명령어로는git merge --squash 브랜치명으로 수행하며, 자동으로 커밋까지 만들지 않고 변경 사항만 합친 뒤 사용자가 수동으로 git commit을 실행해 하나의 커밋을 만들게 됩니다.

📑 Squash 병합 예시

그래프에서 노란 원의 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 제목 등으로 자동 생성하거나, 여러 커밋 메시지를 개행으로 합쳐 편집하게 됩니다.

✅ Squash 병합의 장단점

✅ 장점:

  • 여러 번 나눠 커밋한 작업 내용을 하나로 합칠 수 있기 때문에, 베이스 브랜치의 커밋 히스토리를 매우 깔끔하게 유지할 수 있습니다.
  • 기능 구현 과정에서 자잘한 실험이나 수정 커밋들이 많았다면, Squash Merge로 병합하여 결과물만 한 커밋으로 남기면 메인 히스토리가 단순해집니다. 이렇게 하면 기능 단위로 변화 내용을 한눈에 파악하기도 쉽습니다.
  • develop 등 통합 브랜치에 기능별로 Squash Merge를 사용하고, 나중에 develop 브랜치를 메인에 통째로 병합하는 식의 전략을 많이 사용합니다.

❌ 단점:

  • 개별 커밋들이 사라지기 때문에 세부적인 개발 과정을 히스토리에서 추적하기 어렵다는 단점이 있습니다.
  • 추후에 “어떤 커밋에서 문제 발생했지?”를 조사해야 할 때 모든 변화가 한 커밋에 뭉쳐 있으면 분석이 까다로울 수 있습니다.
  • 병합 커밋을 남기지 않는다는 점에서는 Fast-Forward나 Rebase와 마찬가지로 해당 브랜치가 따로 존재했었다는 흔적이 남지 않습니다.

4. Rebase

🧭 개념

Rebase는 Merge와 달리 커밋 기반을 옮겨 재배치하는 명령입니다.

보통 기능 브랜치를 최신 상태로 업데이트하거나, 병합 대신 히스토리를 다시 쓰는 방식으로 변경 내용을 가져올 때 사용됩니다.
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 커밋 없이도 두 브랜치의 변경 사항이 통합됩니다.

한마디로 “브랜치를 최신 기반으로 미리 맞춘 다음 합치는” 방법이라고 이해할 수 있습니다.

📑 Rebase 예시

노란 원의 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 병합 옵션에서도 제공됩니다.

✅ Rebase 의 장단점

✅ 장점:

  • Fast-Forward처럼 깔끔한 선형 역사를 얻으면서도 Squash처럼 커밋을 하나로 뭉개지 않기 때문에 개별 커밋 단위의 정보가 보존됩니다.
  • 결과 히스토리는 마치 한 브랜치에서 작업한 것처럼 깨끗하지만, 그 안의 커밋들은 원래 브랜치에서 쌓은 순서대로 남아 있으므로 변경 흐름을 상세히 파악할 수도 있습니다. Merge 커밋이 없으므로 이력에 불필요한 커밋이 추가되지 않습니다.
  • develop 등 통합 브랜치에 기능별로 Squash Merge를 사용하고, 나중에 develop 브랜치를 메인에 통째로 병합하는 식의 전략을 많이 사용합니다.

❌ 단점:

  • Rebase를 통해 히스토리를 다시 작성하게 때문에, 협업 중인 브랜치에 함부로 적용하면 충돌이나 혼선을 불러올 수 있습니다.
  • 여러 사람이 함께 작업하고 있는 브랜치에 rebase를 해버리면 다른 사람의 로컬 저장소는 옛 커밋 기록을 가지고 있기 때문에 이후 push/pull 시 심각한 충돌이 생깁니다. 그래서 보통 리베이스는 자신의 로컬 브랜치나 아직 공유되지 않은 브랜치에 한해서 신중하게 사용하는 것이 좋다고 합니다.
  • merge 커밋이 남지 않는다는 특성상, Fast-Forward나 Squash와 마찬가지로 어느 지점에서 분기가 일어났고 합쳐졌는지 흔적을 보기 어렵습니다.
  • rebase 과정에서 커밋 해시가 변경되고, 중간에 충돌을 하나하나 해결해야 할 수도 있으며, 원격 브랜치에 강제 푸시(force push)를 해야 하는 등 난이도가 높습니다.

profile
Pasting my dream in code

0개의 댓글