Merge 충돌

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

Merge 충돌은 Merge Request 내의 두 브랜치(소스 및 대상)가 각각 다른 변경 내용을 가지고 있는 경우 발생하며, 이를 어떤 변경 사항을 수용할지 결정해야 합니다. Merge Request에서 Git은 파일의 두 버전을 라인 단위로 비교합니다. 대부분의 경우, GitLab은 변경 사항을 Merge할 수 있습니다. 그러나 두 브랜치가 동일한 라인을 변경하는 경우, GitLab은 Merge을 차단하고 어떤 변경 사항을 유지할지 선택해야 합니다.

Merge 충돌로 인해 차단된 Merge Request

충돌이 있는 Merge Request은 다음 중 한 가지를 수행하기 전까지 Merge할 수 없습니다:

  • Merge 커밋을 생성합니다.
  • 리베이스를 통해 충돌을 해결합니다.

GitLab은 충돌을 해결하기 위해 Merge 커밋을 소스 브랜치에 생성하지만, 이를 대상 브랜치에 Merge하지는 않습니다. 그 후에 Merge 커밋을 검토하고 테스트할 수 있습니다. 여기에 의도하지 않은 변경 사항이 포함되지 않았는지 확인하고 빌드가 실패하지 않았는지 확인합니다.

충돌 블록 이해

Git이 귀하의 결정이 필요한 충돌을 감지하면 충돌 블록의 시작과 끝을 충돌 표시로 표시합니다:

  • <<<<<<< HEAD는 충돌 블록의 시작을 표시합니다.
  • 여러분의 변경 사항이 표시됩니다.
  • =======는 여러분의 변경 사항의 끝을 표시합니다.
  • 대상 브랜치의 최신 변경 사항이 표시됩니다.
  • >>>>>>>는 충돌의 끝을 표시합니다.

충돌을 해결할 때, 다음을 삭제해야 합니다:

  1. 유지하고 싶지 않은 충돌된 라인의 버전.
  2. 충돌 표시 세 개: 시작, 끝, 그리고 그 사이의 ======= 라인.

사용자 인터페이스에서 해결할 수 있는 충돌

Merge 충돌이 다음 모든 조건을 충족하는 경우, GitLab 사용자 인터페이스에서 Merge 충돌을 해결할 수 있습니다:

  • 파일이 텍스트이고 이진이 아닙니다.
  • 파일이 UTF-8 호환 인코딩입니다.
  • 파일에 이미 충돌 표시가 포함되어 있지 않습니다.
  • 충돌 표시가 추가된 파일의 크기가 200 KB 미만입니다.
  • 파일이 두 브랜치 모두 동일한 경로에 존재합니다.

Merge Request의 모든 파일이 충돌을 포함하지만 이러한 기준을 모두 충족시키지 못하는 경우, 충돌을 매뉴얼으로 해결해야 합니다.

GitLab에서 감지할 수 없는 충돌

GitLab은 두 브랜치가 파일을 서로 다른 이름으로 변경할 때 충돌을 감지하지 못합니다. 예를 들어, 다음과 같은 변경 사항은 충돌을 생성하지 않습니다.

  1. 브랜치 oneexample.txtexample1.txt로 이름을 변경합니다.
  2. 브랜치 twoexample.txtexample_old.txt로 이름을 변경합니다.

이러한 브랜치가 Merge될 때, example1.txtexample_old 둘 다 존재합니다.

충돌 해결 방법

GitLab은 사용자 인터페이스에서 해결할 수 있는 충돌을 보여주며, 명령줄을 통해 충돌을 매뉴얼으로 해결할 수도 있습니다:

  • 대화형 모드: 수정 없이 라인의 어떤 버전을 유지할지 선택할 수 있는 충돌에 가장 적합한 UI 방법입니다.
  • 인라인 편집기: 더 복잡한 충돌로 매뉴얼으로 라인을 편집하고 변경 사항을 매뉴얼으로 혼합해야 하는 경우에 적합한 UI 방법입니다.
  • 명령줄: 가장 복잡한 충돌에 대해 완전한 제어를 제공합니다.

대화형 모드에서

GitLab 사용자 인터페이스를 통해 단순한 충돌을 해결하려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택해 프로젝트를 찾습니다.
  2. Code > Merge Request을 선택하고 Merge Request을 찾습니다.
  3. 개요를 선택하고, Merge Request 보고서 섹션으로 스크롤합니다.
  4. Merge 충돌 메시지를 찾고 충돌 해결을 선택합니다. GitLab은 충돌이 있는 파일 디렉터리을 보여줍니다. 충돌이 있는 행이 강조 표시됩니다:

    충돌 섹션

  5. 각 충돌에 대해 Use ours 또는 Use theirs를 선택하여 유지하려는 충돌된 라인의 버전을 표시합니다. 이 결정을 “충돌 해결”이라고 합니다.
  6. 모든 충돌을 해결한 경우, 커밋 메시지를 입력합니다.
  7. 소스 브랜치에 커밋을 선택합니다.

충돌을 해결하면 Merge Request의 대상 브랜치가 소스 브랜치로 Merge되고, 여러분이 선택한 텍스트 버전이 사용됩니다. 예를 들어, 소스 브랜치가 feature이고 대상 브랜치가 main인 경우, 이 작업은 로컬에서 git switch feature; git merge main을 실행하는 것과 유사합니다.

인라인 편집기에서

일부 Merge 충돌은 더 복잡하며, Merge 충돌을 해결하기 위해 라인을 매뉴얼으로 수정해야 합니다. Merge 충돌 해결 편집기는 GitLab 인터페이스에서 이러한 복잡한 충돌을 해결하는 데 도움을 줍니다:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택해 프로젝트를 찾습니다.
  2. Code > Merge Request을 선택하고 Merge Request을 찾습니다.
  3. 개요를 선택하고, Merge Request 보고서 섹션으로 스크롤합니다.
  4. Merge 충돌 메시지를 찾고 충돌 해결을 선택합니다. GitLab은 충돌이 있는 파일 디렉터리을 보여줍니다.
  5. 직접 편집할 파일을 찾고, 충돌 블록으로 스크롤합니다.
  6. 해당 파일의 머리글에서 편집하기를 선택하여 편집기를 여십시오. 이 예에서 충돌 블록은 1350행에서 시작하여 1356행에서 끝납니다:

    Merge 충돌 편집기

  7. 충돌을 해결한 후 커밋 메시지를 입력합니다.
  8. 소스 브랜치에 커밋을 선택합니다.

명령줄에서

대부분의 충돌은 GitLab 사용자 인터페이스를 통해 해결할 수 있지만, 일부 충돌은 너무 복잡하여 로컬에서 명령줄을 통해 수정하는 것이 가장 좋습니다. 이렇게 하면 각 변경 사항에 대해 가장 많은 제어권을 얻을 수 있습니다.

필수 사항:

  • 브랜치에 강제로 푸시할 수 있는 권한이 있어야 합니다.
  1. 터미널을 열고 feature 브랜치를 확인합니다. 예를 들어, my-feature-branch:

    git switch my-feature-branch
    
  2. 브랜치를 다시 베이스(rebase)로 설정하여 충돌 발생 여부를 확인합니다:

    git fetch
    git rebase origin/main
    
  3. 원하는 코드 편집기에서 충돌 파일을 엽니다.
  4. 충돌 블록을 찾습니다.
  5. 파일을 편집합니다:
    1. 유지하려는 버전(======= 이전 또는 이후)을 선택합니다.
    2. 유지하려는 버전을 삭제합니다.
    3. 충돌 표시를 삭제합니다.
  6. 파일을 저장합니다.
  7. 충돌을 포함하는 각 파일에 대해 이 프로세스를 반복합니다.
  8. Git에서 변경 사항을 스테이징합니다:

    git add .
    
  9. 변경 사항을 커밋합니다:

    git commit -m "Merge 충돌 해결"
    
  10. 리베이스를 계속합니다:

    git rebase --continue
    
    caution
    여기까지 오면 git rebase --abort를 실행하여 프로세스를 중지할 수 있습니다. Git은 리베이스를 중단하고 git rebase를 실행하기 전의 상태로 분기를 되돌립니다. git rebase --continue를 실행한 후에는 리베이스를 중지할 수 없습니다.
  11. 변경 사항을 원격 브랜치로 강제 푸시(force-push)합니다.

관련 주제