<Ju4n_Devlog/>

깃 머지 전략

2024-07-28

들어가며

여러 사람과 협업을 하면서 Git의 브랜치를 병합해야 하는 상황은 불가피하다. 적절한 머지 전략을 선택하는 것은 프로젝트의 히스토리를 관리하는데 매우 중요하다. 어떠한 머지 전략이 적합한지 한번 정리해보자.

Merge

Merge에는 크게 두가지 방식이 많이 사용된다.

Fast-Forward Merge (ff)

Fast-Forward Merge는 병합하려는 두 브랜치 중 하나가 다른 하나의 최신 커밋을 포함하고 있을 때 가능하다. 병합 커밋을 생성할 필요 없이 브랜치 포인터를 단순히 이동시큰 방식으로 병합이 이루어진다.

기본 브랜치 상태

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

Fast-Forward Merge 후

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

장점

  • 단순한 히스토리 : 커밋 히스트리가 직선으로 유지되며, 병합 커밋이 추가되지 않는다.

단점

  • 브랜치 히스토리 소실: 브랜치의 병합 기록이 남지 않아, 브랜치가 언제 병합되었는지 추적하기 어렵다.

  • 단순한 경우에만 사용 가능 : 조건을 만족하지 않으면 사용 할 수가 없다.

    1. 브랜치 A가 브랜치 B의 조상: 브랜치 A의 최상위 커밋이 브랜치 B의 조상이어야한다.

    2. 충돌(conflict) 사항 없음

결론

간단한 병합 작업에서 커밋 히스토리를 직선으로 유지하는데 유용한 방법이다.

그러나 복잡한 병합 시나리오에서는 병합 커밋을 생성하여 히스토리를 명확히 기록하는게 좋을 것이다.

3-Way Merge

Git에서 두 개의 브랜치를 병합할 때 공통 조상을 기준으로 세가지 커밋을 사용하여 병합하는 방법이다. 두 브랜치의 병합 과정에서 충돌을 해결하고, 최종 병합 커밋을 생성하는데 유용하다.

기본 개념

  • 세 가지 커밋:

    1. 공통 조상(commit) : 두 브랜치가 갈라지기 전의 마지막 공통 커밋

    2. 소스 브랜치의 최상위 커밋: 병합하려는 브랜치의 최신 커밋

    3. 타겟 브랜치의 최상위 커밋: 병합 대상 브랜치의 최신 커밋

  • 동작 원리 :

    • Git은 공통 조상을 기준으로 두 브랜치의 변경 사항을 비교한다.

    • 각 브랜치의 변경 사항을 병합하여 새로운 병합 커밋을 생성한다.

    • 충돌이 발생할 경우, 사용자가 충돌을 수동으로 해결해야 한다.

현재 상태

A---B---C---D (main) \ \ E---F G---H (feature)

이 두 브랜치의 공통 조상 커밋은 B 이다.

3-Way Merge 후

A---B---C---D---M (main) \ \ / E---F G---H (feature)

여기서 M 은 병합 커밋으로, main 브랜치의 D 커밋과 feature 브랜치의 H 커밋의 변경 사항을 포함하고 있다.

Rebase Merge

  • 이미 커밋 히스토리 사이사이에 들어가는게 아니라 추가로 하려고하는 커밋들을 뒤에다가 일자로 깔끔하게 해준다.

    • 커밋 해시가 새로 생긴다.

    • 커밋 히스토리 관리는 좋으나 공유된 브랜치를 리베이스를 하면

현재 상태

A---B---C (main) \ D---E---F (feature)

여기서 A, B, Cmain 브랜치의 커밋이고, D, E, Ffeature 브랜치의 커밋이다.

Rebase 후

A---B---C---D'---E'---F' (feature)

여기서 D', E', F'D, E, F 커밋의 새로운 위치입니다. Rebase는 feature 브랜치의 커밋을 main 브랜치의 최상위 커밋 C 뒤로 재배치한다.

장점

  • 깨끗한 히스토리 : 커밋 히스토리가 직선형으로 유지되어 브랜치의 변경 사항을 쉽게 추적할 수 있다.

  • 간결한 로그 : 불필요한 병합 커밋이 없어지고, 커밋 로그가 간결하게 유지된다.

단점

  • 공유 브랜치의 문제 : 이미 공유된 브랜치에서 rebase를 수행하면, 다른 사용자에게 혼란을 줄 수 있다. 커밋 해시가 변경되기 때문에, 충돌이 발생하거나 잘못된 히스토리가 공유될 수 있다.

Squash Merge

Squash Merge는 여러 개의 커밋을 하나의 커밋으로 합쳐서 병합하는 방법이다. 기능 브랜치를 병합할 때 유용하며, 커밋 히스토리를 단순화하고 깔끔하게 유지할 수 있다.

기본 개념

Squash Merge는 소스 브랜치의 모든 커밋을 하나의 커밋으로 압축(squash)한 후, 타겟 브랜치에 병합하는 방법이다. 이는 전체 기능이나 버그 수정 작업을 하나의 커밋으로 병합하여 커밋 히스토리를 간결하게 유지하는 데 도움이된다.

현재 상태

A---B---C (main) \ D---E---F (feature)

여기서 A, B, Cmain 브랜치의 커밋이고, D, E, Ffeature 브랜치의 커밋이다.

수행 후

A-- - B-- - C-- - G(main);

여기서 GD, E, F 커밋을 하나로 합친 커밋으로 main 브랜치에 하나의 커밋으로 병합된다

장점

  • 간결한 히스토리: 여러 개의 커밋을 하나로 합쳐서 병합하므로 커밋 히스토리가 단순하고 깔끔하게 유지된다.

  • 작업 단위 병합: 기능 단위로 병합할 때 유용하며, 전체 작업을 하나의 커밋으로 묶어 병합할 수 있다.

단점

  • 세부 히스토리 소실: 소스 브랜치의 세부적인 커밋 히스토리가 하나의 커밋으로 압축되기 때문에, 세부적인 변경 사항을 추적하기 어렵다.

  • 추적 어려움: 어떤 커밋에서 어떤 변경이 발생했는지 추적하는 데 어려움이 있을 수 있다

수행 방법

# 타겟 브랜치로 체크아웃 git checkout main # 소스 브랜치를 병합하면서 Squash git merge --squash feature # 병합 커밋 생성 git commit -m "Squash merged feature branch" # 병합 결과를 원격 저장소에 푸시 git push origin main

결론

Squash Merge는 여러 개의 커밋을 하나의 커밋으로 압축하여 병합하는 방법으로, 커밋 히스토리를 간결하고 깔끔하게 유지하는 데 유용하다. 기능 단위로 작업을 병합할 때 특히 유용하며, 전체 변경 사항을 하나의 커밋으로 묶어 관리할 수 있다. 그러나 세부적인 커밋 히스토리가 사라질 수 있으므로 주의해야한다.

결론

  • Merge: 복잡한 병합 상황이나 협업 프로젝트에서 브랜치 히스토리를 명확하게 남기고 싶을 때 사용

  • Squash Merge: 여러 개의 작은 커밋을 하나의 커밋으로 합쳐서 병합하고 싶을 때 사용. ex )기능 단위로 작업을 병합할 때

  • Rebase Merge: 브랜치 히스토리를 직선형으로 유지하고, 메인 브랜치와 동기화하고 싶을 때 사용. ex )개인 작업