일반적인 Git 병합 충돌 해결: 단계별 문제 해결 가이드
이 필수 문제 해결 가이드를 통해 Git 병합 충돌을 마스터하세요. 충돌 마커(`<<<<<<<`, `>>>>>>>`)를 식별하고, 수동 해결 전략(로컬 유지, 원격 유지 또는 결합)을 적용하며, 병합 또는 리베이스를 안전하게 완료하는 방법을 배우세요. 충돌 해결을 위한 명확한 단계별 지침을 따라 좌절을 생산성으로 바꾸세요.
일반적인 Git 병합 충돌 해결: 단계별 문제 해결 가이드
Git 병합 충돌은 Git이 겹치는 변경 사항을 발견하여 최종 버전을 선택해야 함을 의미합니다. 일반적으로 두 브랜치가 동일한 줄을 변경하거나, 동일한 파일을 다르게 이름을 바꾸거나, Git이 자동으로 병합할 수 없는 파일을 두 브랜치에서 모두 편집할 때 발생합니다.
목표는 간단합니다. 충돌을 검사하고, 원하는 버전으로 파일을 편집한 후 스테이징한 다음 병합 또는 리베이스를 계속 진행하는 것입니다.
Git 병합 충돌 이해하기
병합 충돌은 Git이 한 브랜치의 변경 사항을 다른 브랜치에 통합하려고 할 때(예: git merge 또는 git rebase 사용) 두 브랜치가 동일한 파일의 동일한 줄을 독립적으로 수정한 경우 발생합니다. Git은 겹치지 않는 변경 사항을 결합하는 데 탁월하지만, 변경 사항이 직접 겹치는 경우 사람의 개입이 필요합니다.
Git이 충돌을 알리는 방법
병합 중 충돌이 발생하면 Git은 즉시 작업을 중단하고 병합이 실패했음을 알립니다. 영향을 받은 파일은 작업 디렉토리에서 충돌 상태로 표시됩니다. 다음 명령어로 상태를 확인할 수 있습니다:
git status
출력에는 "병합되지 않은 경로" 파일이 나열되며, 병합을 진행하기 전에 수동으로 해결해야 함을 나타냅니다.
1단계: 충돌 표시 식별
Git이 병합을 중단하면 충돌 파일에는 Git이 삽입한 특수 표시가 포함되어 충돌 섹션을 구분합니다. 이 표시는 각 브랜치에서 어떤 변경 사항이 왔는지 정확히 보여줍니다.
충돌 표시
일반 텍스트 충돌에서는 두 버전의 콘텐츠를 둘러싼 세 개의 표시 줄이 표시됩니다:
<<<<<<< HEAD:- 현재 브랜치(병합 대상 브랜치)의 변경 사항 시작을 표시합니다.
=======:- 두 충돌 변경 사항 집합 사이의 구분자 역할을 합니다.
>>>>>>> branch-name:- 들어오는 브랜치(병합 소스 브랜치)의 변경 사항 끝을 표시합니다.
충돌 블록 예시:
feature/A를 main에 병합 중이고 두 브랜치가 config.js의 10번째 줄을 편집했다고 가정합니다:
// config.js
function getTimeout() {
<<<<<<< HEAD
return 5000; // Main branch default
=======
return 10000; // Feature A override
>>>>>>> feature/A
}
2단계: 파일 편집으로 충돌 해결
충돌 해결은 Git 표시를 제거하고 원하는 코드 조합을 선택하기 위해 파일을 편집하는 것을 포함합니다. 세 가지 주요 해결 전략이 있습니다:
A. HEAD(현재 브랜치)의 변경 사항 유지
현재 브랜치(HEAD)의 버전이 올바르다고 판단되면 들어오는 변경 사항과 모든 표시를 제거합니다.
해결 작업:
// config.js
function getTimeout() {
return 5000; // Main branch default
}
B. 들어오는 브랜치의 변경 사항 유지
병합 중인 브랜치의 변경 사항이 올바르다고 판단되면 현재 브랜치의 변경 사항과 모든 표시를 제거합니다.
해결 작업:
// config.js
function getTimeout() {
return 10000; // Feature A override
}
C. 변경 사항 결합 또는 다시 작성(하이브리드 접근 방식)
종종 최상의 해결책은 양쪽의 로직을 통합하는 새 버전을 수동으로 구성하거나 두 원래 수정 사항의 요구 사항을 충족하도록 코드를 완전히 다시 작성하는 것입니다.
해결 작업(하이브리드 예시):
// config.js
function getTimeout() {
// 환경 변수에 따라 타임아웃 설정, 로직 결합
if (process.env.NODE_ENV === 'production') {
return 10000;
}
return 5000;
}
모범 사례: 충돌 블록을 해결한 후 결과 코드가 컴파일되고 올바르게 작동하는지 항상 확인하세요. 이 단계에서 단위 테스트를 실행하는 것이 좋습니다.
3단계: 해결된 파일 스테이징
모든 충돌 파일을 수동으로 편집하여 모든 <<<<<<<, =======, >>>>>>> 표시를 제거한 후에는 이러한 변경 사항을 스테이징하여 Git에 충돌이 처리되었음을 알려야 합니다.
해결한 각 파일에 대해 표준 git add 명령을 사용합니다:
git add config.js
git add src/utils/helper.py
# ... 모든 충돌 파일에 대해 반복
Git이 해결을 인식하는지 확인하려면 git status를 다시 실행하세요. 이전에 병합되지 않은 모든 경로는 이제 "커밋할 변경 사항" 아래에 표시됩니다.
4단계: 병합 또는 리베이스 완료
모든 충돌이 스테이징되면 시작된 원래 명령에 따라 작업을 마무리합니다:
git merge 완료
표준 병합을 수행 중인 경우 커밋으로 마무리합니다:
git commit
Git은 일반적으로 미리 채워진 병합 커밋 메시지와 함께 구성된 텍스트 편집기를 엽니다. 검토하고 저장한 후 편집기를 닫습니다. 병합이 완료됩니다.
git rebase 완료
리베이스 중인 경우 프로세스를 계속하여 해결된 상태 위에 후속 커밋을 적용합니다:
git rebase --continue
리베이스 시퀀스의 후속 커밋도 충돌을 일으키면 각 충돌에 대해 2~4단계를 반복합니다.
어려운 충돌 문제 해결 팁
위 단계는 표준 해결을 다루지만, 복잡한 시나리오에서는 대체 접근 방식이 필요할 수 있습니다:
작업 중단
병합 또는 리베이스를 시작했는데 상황이 너무 복잡하거나 팀원과 상담해야 한다고 판단되면 명령 실행 전 상태로 되돌릴 수 있습니다:
git merge --abort # 'git merge'로 시작한 경우
git rebase --abort # 'git rebase'로 시작한 경우
시각적 diff 도구 사용
겹치는 변경 사항이 많은 복잡한 파일의 경우 전용 3방향 병합 도구(VS Code의 내장 병합 편집기, KDiff3 또는 Meld 등)를 사용하는 것이 좋습니다. 구성된 도구를 직접 실행할 수 있습니다:
git mergetool
이 인터페이스는 로컬 버전, 원격 버전 및 공통 조상을 표시하여 수동 선택을 훨씬 명확하게 만듭니다.
바이너리 파일 처리
Git은 바이너리 파일(이미지 또는 컴파일된 자산 등)을 자동으로 병합할 수 없습니다. 두 브랜치가 동일한 바이너리 파일을 수정하면 Git이 충돌을 보고합니다. 이 경우 선호하는 파일을 작업 디렉토리에 복사하고 스테이징한 후 커밋/계속하여 유지할 버전을 수동으로 선택해야 합니다.
# 병합 중 현재 브랜치의 버전 유지
git checkout --ours image.png
# 또는 병합 중인 브랜치의 버전 유지
git checkout --theirs image.png
git add image.png
git commit
리베이스 중에는 Git이 커밋을 새 베이스에 재생하기 때문에 --ours와 --theirs가 반대로 느껴질 수 있습니다. git status를 실행하고 파일을 검사한 후 스테이징하기 전에 선택한 버전을 확인하세요.
핵심 요점
표시를 무작정 삭제하여 "충돌을 제거"하려고 하지 마세요. 양쪽을 읽고 최종 코드가 무엇이어야 하는지 결정한 후 관련 테스트를 실행하고 해결된 파일을 스테이징하세요. 그런 다음 병합의 경우 git commit, 리베이스의 경우 git rebase --continue를 사용하세요.