Skip to content

[학습공유] 머지 방법과 장단점

Hyunjun edited this page Jan 8, 2025 · 1 revision

🫠 문제 상황?

  • 항상 머지에 대해 이야기하면 이렇게 되는 것 같습니다. (본인 기준)
  • 스쿼시 머지가 이랬던 것 같은데...
  • 이거 장단점이 이랬던 것 같은데...
  • 아마 그럴껄요?
  • 정확히 어떻게 되는거죠?

목표는 이제 당당히 머지가 어떻게 되는지 장단점이 어떻게 되는지 말할 수 있게!

Merge의 기초

  • 이 문서는 Merge에 대한 어느정도 이해를 기반으로 작성되어 있습니다.
  • Merge의 기초...? 모르겠다 → 공식문서를 보시면 친절하게 설명이 되어있습니다.

Github에서 Merge pull request의 옵션 세가지

Github에서 Merge를 하게 되면 아래의 세가지 옵션을 확인할 수 있습니다.

  • Create a merge commit
  • Squash and merge
  • Rebase and merge

Create a merge commit3-way Merge를 말하는 것인데... Squash merge, Rebase merge가 아닌 and가 붙은 이유를 살펴보아야 합니다.

Merge의 두가지 방법

  • git이 Merge를 하는 공식문서에서 설명하는 방식은 두가지 입니다. 바로 Fast-forward Merge, 3-way Merge

Fast-forward Merge

아래와 같은 작업 상황에서 머지를 하게 된다면

A -- B (main)
       \
        D -- E (dev)

Fast-forward 메세지가 뜨면서 머지가 됩니다.

머지를 하게된다면 main 브랜치dev 브랜치의 최신으로 옮겨가면서 아래와 같은 모양이 되겠죠?

A -- B
       \
        D -- E (main, dev)

3-way Merge

아래와 같은 작업 상황에서 머지를 하게 된다면

A -- B -- C (main)
       \
        D -- E (dev)

Merge made by the 'ort' strategy.와 같은 메세지를 볼 수 있습니다.

아래와 같이 공동 조상인 B을 기준으로 CE를 병합합니다.

A -- B -- C -- M (main)
     \        /
      D --- E (dev)

자 참고로 여기서 메세지에서 'ort' strategy. 라고 나오는데, 공식문서에서는 'recursive' strategy. 로 예시가 보이는데 차이가 뭘까요?

  • 2021년 git 2.33.0 버전에서 새로 업데이트 된 3-way Merge의 방식이 변경된 것이라고 보면 될 것 같습니다.
  • git 2.33 공지에 따르면 복잡한 머지가 500배가 빨라지는 등 성능 개선이 있다고 합니다.
  • Merge전략은 resolve → recursive → ort 순으로 발전하였고, ort는 Ostensibly Recursive’s Twin의 약자입니다. 더 자세한 내용을 알아보고 싶지만 그렇게 된다면 오늘 밤을 새야할 것이기 때문에 생략하도록 하겠습니다...
  • 위에서 설명한 머지의 경우는 아주 단순한 경우에 속하고, 파일명 변경, 디렉토리 변경등 여러 사항이 포함된다면 git은 파일의 내용을 추적하고 파일명은 추적하지 않고 있기 때문에 추적해야하는 파일의 복잡성은 올라가게 되고, 이를 개선하기 위한 알고리즘이 새로 나왔다 정도만 파악해두면 좋을 것 같습니다.
  • 제대로 알고 싶으시다면 ort 전략 공식문서를 참고해보셔도 좋을 것 같습니다. (영어입니다)

세가지 Merge의 비교

다시 본론으로 돌아와서 아래의 화면이 기억 나시나요? 하나하나 살펴봅시다.

Create a merge commit

  • 3-way Merge방식으로 머지합니다.

Squash and merge

  • 브랜치 상태가 아래와 같다고 가정해 봅시다.
A -- B -- C (main)
       \
        D -- E -- F (dev)
  • Squash and merge를 하게 된다면 아래와 같이 됩니다. D, E, F 커밋이 M 커밋 하나로 합쳐지게 되고 main 브랜치 끝에 추가됩니다.
A -- B -- C -- M (main)
       \
        D -- E -- F (dev)
  • D, E, F의 개별 히스토리는 유지되지 않습니다. 로컬에 있는 레포를 지우고 클론을 다시 한다면 해당 커밋으로 이동하는 것은 불가능하다는 것을 확인했습니다.
  • Squash and merge3-way Merge도 아니고, Fast-forward도 아닙니다. 단순히 커밋을 하나로 합친 뒤 새로운 커밋을 생성하고 합쳐지는 브랜치의 최신커밋과 비교합니다.

Rebase and merge

  • RebaseFast-forward Merge를 결합한 병합 방식입니다. 아래와 같은 상황이라고 한다면
A -- B -- C (main)
       \
        D -- E -- F (dev)
  • 아래와 같이 병합 대상 브랜치(dev)의 모든 커밋(D, E, F)을 타겟 브랜치(main)의 최신 커밋(C) 뒤로 재배치합니다.
  • 여기서 D', E', F'D, E, F 커밋의 복사본으로, 새로운 부모 커밋(C)을 기반으로 재작성된 상태입니다.
A -- B -- C (main)
           \
            D' -- E' -- F' (dev)
  • 타겟 브랜치(main)를 병합 대상 브랜치(dev)의 최신 커밋(F')으로 이동합니다.
A -- B -- C
           \
            D' -- E' -- F' (main, dev)
  • 아래와 같이 rebase를 하면 C20, C21이 복사된 새로운 커밋이 C23위에 생기는 것을 볼 수 있습니다.

장단점 비교

이 세가지중 어떤 것을 채택해야 할까요? 표로 정리해 봅시다.

특징 Create a merge commit Squash and merge Rebase and merge
히스토리 구조 브랜치 간 분기와 병합 관계 유지 병합 대상 브랜치의 커밋을 하나로 압축하여 단일 커밋 생성 히스토리를 선형화하여 브랜치 간 분기와 병합 관계 제거
병합 커밋 생성됨 생성되지 않음 생성되지 않음
세부 커밋 유지 유지됨 유지되지 않음(모든 커밋이 하나로 압축됨) 유지됨
로그 가독성 복잡해질 수 있음 깔끔한 로그 유지 깔끔한 로그 유지
브랜치 관계 추적 브랜치 간 병합 관계를 추적 가능 브랜치 간 관계가 로그에서 사라짐 브랜치 간 관계가 로그에서 사라짐
충돌 처리 병합 시 한 번에 충돌 해결 병합 시 한 번에 충돌 해결 Rebase 중 각 커밋별로 충돌 해결
협업 친화성 협업에 안전 협업에 적합(히스토리 단순화) 협업 시 신중히 사용해야 함(커밋 ID 변경 가능성 있음)
사용 사례 병합 관계를 명확히 기록하고 싶은 경우 기능 단위로 변경 사항을 압축하여 히스토리를 단순화하고 싶은 경우 히스토리를 선형화하면서 세부 커밋 정보를 유지하고 싶은 경우
장점 - 병합 관계를 명확히 유지
- 충돌 해결 히스토리 기록
- 히스토리가 단순화되어 가독성 높음 - 히스토리가 선형화되어 깔끔
- 세부 커밋 유지
단점 - 로그가 복잡해짐
- 불필요한 병합 커밋
- 브랜치 간 병합 관계가 사라짐
- 세부 커밋 히스토리 손실
- 커밋 ID 변경으로 협업 시 주의
- Rebase 중 충돌 해결 부담

복...잡하죠? 아주 간단하게 정리해보겠습니다.

커밋 히스토리 vs 브랜치 히스토리

  • 커밋 히스토리가 복잡하더라도 브랜치 히스토리를 파악하고 싶다. → Create a merge commit
  • 커밋 히스토리를 깔끔하게 관리하고 싶다. → Squash and merge, Rebase and merge

커밋 디테일 vs 커밋 간결성

  • 커밋 하나하나 추적이 가능해야 한다. 이를 위해 커밋별 충돌이 일어나도 해결할 것이다. → Rebase and merge
  • 중요한 작업 커밋만 알고있으면 된다. 커밋을 최대한 깔끔하게 유지하고 싶다. → Squash and merge
Clone this wiki locally