A. Question

GIT 병합 전략에는 어떤 것들이 있는가?

B. Answer

1. Fast-Forward Merge

(1) 개념

  • Fast-Forward Merge는 병합 대상 브랜치가 직선형 히스토리로 이어질 수 있는 경우 발생한다.
  • 병합 시 새로운 병합 커밋이 생성되지 않고, 대상 브랜치의 HEAD가 병합하려는 브랜치의 HEAD로 단순히 이동한다.

(2) 동작 조건

  • 공통 조상 이후, 대상 브랜치에 새로운 커밋이 없을 때
    • 예: main 브랜치가 C2에서 멈춘 상태이고, feature 브랜치에만 추가 커밋 C4가 있는 경우
  • 두 브랜치가 공통 히스토리를 유지하며 분기되지 않은 상태

(3) 예시

  • Before Merge

    main:    C0 → C1 → C2
    feature:              → C3
    
  • After Fast-Forward Merge

    main:    C0 → C1 → C2 → C3
    

(4) 명령어

  # main 브랜치로 이동
  git checkout main
  
  # feature 브랜치를 Fast-Forward 방식으로 병합
  git merge feature

(5) 장단점

  • 장점
    • 히스토리가 단순하고 깔끔하게 유지된다.
    • 추가 병합 커밋이 생성되지 않아 로그가 간결하다.
  • 단점
    • 브랜치 병합 이력이 명확히 표시되지 않아 추적이 어려울 수 있다.
    • 변경 내용이 많거나 중요한 경우에는 적합하지 않을 수 있다.

(6) Fast-Forward Merge가 불가능한 경우

  • 대상 브랜치 main에 새로운 커밋이 존재하는 경우
  • 두 브랜치 mainfeature가 공통 조상 이후 각각 독립적으로 변경 사항을 가지는 경우

이 경우 Non-Fast-Forward Merge 또는 Recursive Merge(3-way Merge)가 수행된다.

(7) Fast-Forward Merge를 강제하지 않는 방법

작업 이력을 명확히 구분하고 싶을 때, 롤백이 용이해야 할 때, 혹은 대규모 프로젝트에서 병합 이력이 중요한 경우, Fast-Forward Merge 대신 병합 커밋을 생성하는 것이 유리하다.

  • --no-ff 옵션을 사용하면 Fast-Forward Merge 대신 병합 커밋이 생성된다.

    git merge --no-ff feature
    

2. Recursive Merge (3-Way Merge)

(1) 개념

  • Recursive Merge는 두 브랜치 간 공통 조상 커밋을 기준으로, 병합하려는 브랜치와 대상 브랜치의 변경 사항을 비교하고 병합하는 방식이다.
  • 3-Way Merge라고도 불리며, 두 브랜치가 공통 조상 이후 서로 독립적인 변경 사항을 가지고 있을 때 수행된다.
  • 병합 결과로 새로운 병합 커밋이 생성된다.

(2) 동작 조건

  • 두 브랜치가 공통 조상 이후 각각 독립적인 변경 사항을 가질 때 발생한다.
  • 대상 브랜치 main에 새로운 커밋이 존재하거나, 병합하려는 브랜치와 충돌이 발생할 가능성이 있는 경우.

(3) 예시

  • Before Merge

    main:    C0 → C1 → C2 → C3
    feature:              → C4
    
  • After Recursive Merge

    main:    C0 → C1 → C2 → C3 → M (merge commit)
                           ↘       ↗
                             → C4
    
  • C2는 두 브랜치의 공통 조상 커밋이다.
  • C3(main)C4(feature)의 변경 사항을 병합하여 병합 커밋 M을 생성한다.

(4) 명령어

  # main 브랜치로 이동
  git checkout main
  
  # feature 브랜치를 병합 (Recursive Merge 자동 수행)
  git merge feature

(5) 장단점

  • 장점
    • 병합 이력이 명확하게 표시되므로, 브랜치 간 병합 내용을 추적하기 용이하다.
    • 충돌이 발생할 경우, 충돌 부분을 명시적으로 해결할 수 있다.
    • 두 브랜치의 독립적인 변경 사항을 모두 병합하여, 최종 결과를 생성한다.
  • 단점
    • 병합 커밋이 추가로 생성되기 때문에, 히스토리가 복잡해질 수 있다.
    • 충돌이 발생하면 수동으로 해결해야 하므로, 시간이 더 소요될 수 있다.

(6) 충돌 발생 시 처리 방법

  • 충돌 확인: 병합 도중 충돌이 발생하면, Git은 이를 감지하고 충돌 파일을 표시한다.

    git status
    
  • 충돌 파일 수정: 충돌이 발생한 파일에 다음과 같은 표시가 나타난다. 충돌 부분을 수동으로 수정한다.

    <<<<<<< HEAD
    (main 브랜치의 변경 사항)
    =======
    (feature 브랜치의 변경 사항)
    >>>>>>> feature
    
  • 병합 완료: 충돌을 해결한 뒤, 수정한 파일을 스테이징하고 병합을 완료한다.

    git add <file>
    git commit
    

3. Squash Merge

(1) 개념

  • Squash Merge는 병합 대상 브랜치의 모든 커밋을 하나로 합쳐 단일 커밋으로 병합하는 방식이다.
  • 병합 후, 대상 브랜치에는 병합 브랜치의 세부 커밋 내역이 기록되지 않고 하나의 커밋만 추가된다.
  • 주로 작업 내역을 단순화하거나, 작업 단위로 정리하고 싶을 때 사용된다.

(2) 동작 조건

  • 대상 브랜치와 병합 브랜치 간에 충돌이 없거나, 충돌을 해결한 뒤 병합할 수 있다.
  • 병합 시 기존 브랜치의 커밋 히스토리는 병합 브랜치에 포함되지 않는다.

(3) 예시

  • Before Merge

    main:    C0 → C1 → C2
    feature:              → F1 → F2 → F3
    
  • After Squash Merge

    main:    C0 → C1 → C2 → S1
    
  • S1feature 브랜치의 모든 커밋 F1, F2, F3을 하나로 압축한 커밋이다.
  • 병합 브랜치 feature의 개별 커밋은 대상 브랜치 main에 남지 않는다.

(4) 명령어

  # main 브랜치로 이동
  git checkout main
  
  # feature 브랜치를 Squash 방식으로 병합
  git merge --squash feature
  
  # Squash된 변경 사항을 커밋
  git commit -m "Squash feature branch into main"

(5) 장단점

  • 장점
    • 히스토리를 단순화하여 로그를 깔끔하게 유지할 수 있다.
    • 작업 브랜치의 세부 작업 내역을 노출하지 않아도 된다.
    • 대상 브랜치에 필요한 결과만 남기므로, 커밋 단위가 많아 복잡한 작업에 적합하다.
  • 단점
    • 병합 브랜치의 세부 커밋 내역이 사라지므로, 변경 이력을 상세히 추적하기 어렵다.
    • 브랜치 간 병합 이력이 명확히 표시되지 않아, 협업 시 작업 내역을 파악하기 어려울 수 있다.

4. Rebase and Merge

(1) 개념

  • Rebase and Merge는 병합 브랜치의 커밋을 대상 브랜치의 최신 커밋 위로 재배치하여 병합하는 방식이다.
  • 병합 커밋 없이 두 브랜치의 커밋 히스토리를 직선형으로 정리한다.
  • 마치 병합 브랜치가 대상 브랜치에서 바로 작업한 것처럼 히스토리를 재정렬한다.

(2) 동작 조건

  • 병합하려는 브랜치와 대상 브랜치 모두에 충돌이 없거나, 충돌이 해결된 경우.
  • 병합 커밋을 생성하지 않고 히스토리를 간소화하려는 경우.

(3) 예시

  • Before Merge

    main:    C0 → C1 → C2
    feature:              → F1 → F2
    
  • After Rebase and Merge

    main:    C0 → C1 → C2 → F1 → F2
    
  • 병합 브랜치 featuer의 커밋 F1, F2가 대상 브랜치 main의 최신 커밋 C2 위에 재배치된다.
  • 별도의 병합 커밋이 생성되지 않고, 히스토리가 직선형으로 정리된다.

(4) 명령어

  # feature 브랜치를 대상으로 Rebase 수행
  git checkout feature
  git rebase main
  
  # main 브랜치로 이동 후 병합
  git checkout main
  git merge feature

(5) 장단점

  • 장점
    • 히스토리가 직선형으로 정리되어 로그가 깔끔해지고, 작업 흐름이 명확히 보인다.
    • 병합 커밋 없이 변경 사항을 대상 브랜치에 자연스럽게 적용할 수 있다.
    • 대상 브랜치와 병합 브랜치의 커밋이 모두 유지되므로, 작업 내역을 상세히 추적할 수 있다.
  • 단점
    • Rebase 중 충돌이 발생하면, 모든 충돌을 단계적으로 해결해야 하며, 병합보다 번거로울 수 있다.
    • Rebase는 커밋 히스토리를 재작성하므로, 이미 공유된 브랜치에서 Rebase를 사용하면 협업 중 혼란을 초래할 수 있다.
    • 어떤 브랜치가 병합되었는지 로그에서 바로 확인하기 어렵다.

5. Merge 방식 비교

특징 Rebase and Merge Squash Merge Recursive Merge (3-Way Merge) Fast-Forward Merge
병합 커밋 생성 여부 병합 커밋 생성되지 않음 커밋 압축 후 단일 커밋 생성 병합 커밋 생성 병합 커밋 생성되지 않음
히스토리 구조 직선형으로 정리 단일 커밋으로 정리 병합 이력이 명확히 표시됨 직선형 히스토리 유지
작업 세부 기록 병합 브랜치의 세부 커밋 보존 병합 브랜치의 세부 커밋 삭제 병합 브랜치와 대상 브랜치 이력 보존 병합 브랜치와 대상 브랜치가 동일화
적합한 상황 직선형 히스토리를 만들고 싶을 때 작업 단위를 간소화하고 싶을 때 독립적인 변경 사항을 병합할 때 대상 브랜치에 변경 사항이 없을 때
장점 작업 흐름이 깔끔하고 히스토리가 간결 히스토리 단순화, 로그가 깔끔 변경 내역 추적이 명확 추가 커밋 없이 간단한 병합 가능
단점 충돌 해결이 번거롭고, 공유 브랜치에서 사용 시 위험 세부 커밋 내역이 사라져 추적 어려움 히스토리가 복잡해질 수 있음 병합 이력이 명확하지 않아 추적 어려움

D. Reference

태그:

카테고리:

업데이트:

댓글남기기