🔍 검색 키워드: git merge conflict 해결, git 충돌 해결, merge conflict 뜨는 이유, rebase conflict, git pull 충돌, git 머지 에러
왜 merge conflict가 생기는가
두 사람이 같은 파일의 같은 줄을 각자 다르게 수정하면 Git은 어느 쪽을 선택해야 할지 모른다. 그래서 멈추고 사람한테 결정을 넘긴다. 그게 전부다. 무서운 게 없다.
레벨 1 — 기초: 충돌 마커 읽기
충돌이 생기면 Git은 파일 안에 이런 마커를 심어준다.
<<<<<<< HEAD
const greeting = "안녕하세요"; // 내 변경사항
=======
const greeting = "Hello"; // 상대방 변경사항
>>>>>>> feature/english-greeting
<<<<<<< HEAD~=======: 현재 브랜치(내 것)=======~>>>>>>>: 병합 대상 브랜치(상대 것)
해결 방법은 단순하다. 둘 중 하나를 고르거나, 둘 다 합치거나, 완전히 새로 쓰거나. 마커 3개(<<<<<<<, =======, >>>>>>>)를 모두 제거하고 원하는 최종 코드만 남기면 된다.
# 충돌 파일 확인
git status
# 수동 편집 후
git add src/greeting.js
git commit
레벨 2 — 실무: 자주 마주치는 상황별 대처
상황 1: git pull 했더니 충돌 폭탄
git pull origin main
# CONFLICT (content): Merge conflict in src/api.js
# Automatic merge failed; fix conflicts and then commit the result.
| 단계 | 명령어 | 설명 |
|---|---|---|
| 1 | git status | 충돌 파일 목록 확인 |
| 2 | 에디터에서 파일 열기 | 마커 찾아서 수동 편집 |
| 3 | git add <파일> | 해결된 파일 스테이징 |
| 4 | git commit | 머지 커밋 생성 (메시지 자동 입력됨) |
상황 2: merge 중 충돌, 그냥 포기하고 싶을 때
git merge --abort
--abort 하면 merge 시작 전 상태로 되돌아간다. 깔끔하게 포기할 수 있다.
상황 3: rebase 중 충돌
git rebase main
# CONFLICT (content): Merge conflict in src/user.js
rebase는 커밋 하나씩 재적용하기 때문에 충돌도 커밋 단위로 난다.
# 각 충돌 해결 후
git add src/user.js
git rebase --continue # 다음 커밋으로 진행
# 포기할 때
git rebase --abort
상황 4: 특정 파일을 그냥 한 쪽으로 덮어쓰고 싶을 때
# 내 것(HEAD) 으로 덮어쓰기
git checkout --ours src/config.js
# 상대 브랜치 것으로 덮어쓰기
git checkout --theirs src/config.js
git add src/config.js
레벨 3 — 고급: 도구 활용 및 예방
VS Code에서 충돌 해결
VS Code는 충돌 파일에 시각적 버튼을 표시해준다.
- Accept Current Change → HEAD 것 선택
- Accept Incoming Change → 병합 대상 것 선택
- Accept Both Changes → 둘 다 유지
- Compare Changes → diff 보기
터미널보다 훨씬 빠르다. 파일이 많을 때 특히 유용하다.
git mergetool 사용
# VS Code를 mergetool로 설정
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
git mergetool
Python 프로젝트: requirements.txt 충돌
<<<<<<< HEAD
requests==2.28.0
=======
requests==2.31.0
>>>>>>> feature/update-deps
보통 높은 버전을 선택하되, 호환성 깨지는 메이저 버전 업이면 테스트 먼저.
Node.js: package-lock.json 충돌
package-lock.json 충돌은 직접 해결하려 하지 말고 이게 낫다.
# 충돌난 package-lock.json 삭제 후 재생성
git checkout --theirs package-lock.json
npm install
# 또는 아예 새로 생성
rm package-lock.json
npm install
git add package-lock.json
Java/Spring: application.yml 충돌
server:
port: 8080 # <-- HEAD vs 8081 충돌 예시
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
환경별 설정이 섞이는 케이스. application-dev.yml, application-prod.yml로 분리하면 근본 해결된다.
Nginx 설정 파일 충돌
location /api {
proxy_pass http://localhost:3000;
proxy_set_header X-Real-IP $remote_addr; # incoming 것 추가
}
두 변경사항을 합치는 게 맞다. 헤더 추가된 버전에 로컬 주소를 넣거나, 환경변수로 빼거나.
충돌 자주 나는 상황 진단표
| 상황 | 원인 | 예방법 |
|---|---|---|
| pull할 때마다 충돌 | 브랜치가 너무 오래됨 | 자주 rebase/merge |
| 같은 파일 반복 충돌 | 역할 분리 안 됨 | 파일 소유권 명확히 |
| package-lock.json 항상 충돌 | 여러 명이 npm install | CI에서만 lock 갱신 |
| config 파일 충돌 | 환경 설정 공유 | 환경별 파일 분리 |
| 이진 파일(이미지 등) 충돌 | .gitattributes 없음 | 이진 파일 전략 설정 |
.gitattributes로 이진 파일 전략 설정
# 이진 파일은 충돌 없이 무조건 덮어쓰기
*.png binary
*.jpg binary
*.pdf binary
# package-lock.json은 theirs 전략
package-lock.json merge=theirs
실수하기 쉬운 것들
1. 마커 제거 안 하고 커밋
# 커밋 전 마커 잔존 여부 확인
grep -r "<<<<<<< " src/
CI에 충돌 마커 검사 스텝 추가해두면 실수 방지된다.
2. rebase 후 force push
rebase 완료 후 원격에 올릴 때는 --force 대신 이걸 써라.
git push --force-with-lease origin feature/my-branch
남이 push한 게 있으면 실패해서 안전하다.
요약
- 충돌 마커(
<<<<<<<,=======,>>>>>>>) 3개 찾아서 제거하고 원하는 코드 남기면 끝 - 포기하고 싶으면
git merge --abort또는git rebase --abort - VS Code mergetool 설정해두면 시간 절약
- package-lock.json은 직접 고치지 말고 재생성
- 충돌 자주 나면 브랜치 수명을 짧게 가져가는 게 근본 해결책
댓글 없음:
댓글 쓰기