Git 원격 변경과 내 수정이 겹쳤을 때: fetch부터 충돌 해결까지 안전하게 병합하기
미커밋 수정, 갈라진 커밋, 실제 충돌을 구분하고 작업을 보존해 병합하는 절차다. Git 2.52.0의 로컬 재현으로 백업 브랜치·stash·merge abort의 경계를 검증한다.
두 갈래 변경을 합치고 원본 기록을 별도로 남기는 모습을 표현한 생성형 개념 이미지다. 실제 Git 화면이나 내부 구조도는 아니다.
원격 저장소의 변경과 내 수정이 겹쳤다면, 곧바로 강제 명령을 실행하지 않는다. 먼저 아직 커밋하지 않은 수정인지, 양쪽 커밋이 갈라진 것인지, 이미 병합 충돌이 발생한 것인지 구분한다. 작업을 보존하고 fetch로 비교한 뒤, 필요한 경우에만 병합하는 순서가 안전하다.
이 글은 현재 브랜치가 main, 비교할 원격 추적 브랜치가 origin/main인 예시다. 실제 저장소의 이름과 팀의 병합 정책으로 바꿔 적용한다. 명령 묶음을 처음부터 끝까지 무조건 실행하는 절차가 아니다.
작성·공식 문서 확인: 2026-11-04 한국 시간. 실행 검증: Git 2.52.0, 임시 로컬 저장소. 실제 프로젝트·인증정보·외부 원격 서버는 사용하지 않았으며 push도 실행하지 않았다.
1. ‘겹쳤다’는 말을 세 가지 상태로 나눈다
Your local changes ... would be overwritten는 미커밋 수정이 덮일 수 있어 Git이 통합을 시작하지 않은 상황이다. 이때는 충돌 표시를 찾기보다 작업 보존이 먼저다.
ahead 1, behind 1은 로컬에만 있는 커밋 하나와 원격 추적 브랜치에만 있는 커밋 하나가 있다는 뜻이다. 서로 다른 파일을 고쳤다면 자동으로 합쳐질 수 있다. 숫자만 보고 충돌로 판단하지 않는다.
CONFLICT, Unmerged paths, UU는 실제 통합 시 자동 해결하지 못한 경로가 생겼다는 신호다. 다만 stash apply에서도 이런 상태가 나올 수 있으므로, 직전에 실행한 명령까지 확인한다. 세 경우의 차이는 아래 임시 저장소 실험에서도 재현했다.
pull이 merge와 rebase 중 방식을 지정하라고 멈춘 상황 역시 내용 충돌과 별개다. 불확실한 상황에서는 가져오기와 통합을 분리하면 상태를 파악하기 쉽다.
2. 현재 작업과 비교 대상을 먼저 확인한다
git status가 이미 merge나 rebase 진행 중이라고 표시하면 새 동기화를 시작하지 말고 해당 작업부터 마무리하거나 취소한다. 브랜치 이름이 비어 있는 detached HEAD 상태라면 아래 예시를 그대로 진행하지 않는다. remote -v 출력에는 비공개 주소나 잘못 저장된 인증정보가 있을 수 있으므로 그대로 공유하지 않는다.
현재 브랜치와 원격이 의도한 대상임을 확인했다면 가져오기만 수행한다.
일반적인 원격 추적 설정에서 fetch는 원격 변경을 가져와 origin/main 같은 참조를 갱신하며 현재 브랜치에 자동 병합하지 않는다. Git fetch 공식 문서
위 rev-list의 왼쪽 숫자는 현재 HEAD에만 있는 커밋 수, 오른쪽은 origin/main에만 있는 수다. 0 3이면 원격 쪽만 앞서 있고, 2 3이면 양쪽 이력이 갈라져 있다. 0 0이라도 미커밋 수정이 없는 것은 아니므로 status와 함께 읽는다. Git rev-list 공식 문서
3. 백업 브랜치와 미커밋 작업 보관은 다르다
이 명령은 현재 커밋 위치를 남긴다. 같은 이름이 이미 있다면 다른 이름을 쓴다. 백업 브랜치는 작업 중인 파일이나 미추적 파일의 별도 사본이 아니다. Git branch 공식 문서
미커밋 작업이 있다면 변경을 검토해 필요한 경로만 커밋하거나 임시 보관한다. 완성되지 않은 수정이라면 다음처럼 stash를 만들 수 있다.
새 항목이 실제로 만들어졌는지 확인한다. 변경이 없어서 stash가 생기지 않았다면 기존 stash@{0}을 이번 보관본이라고 착각하면 안 된다.
-u는 미추적 파일도 포함하지만 ignored 파일까지 보관하지는 않는다. 중요한 로컬 설정·데이터는 필요에 따라 별도 보관한다. 무시 파일까지 정리하는 -a를 무작정 대체 옵션으로 쓰지 않는다. 작업 트리와 인덱스가 준비됐는지 다시 확인한 뒤 통합한다. Git stash 공식 문서
4. 커밋 관계에 따라 한 가지 경로를 고른다
작업 보관 중 새 커밋을 만들었다면 git rev-list --left-right --count HEAD...origin/main으로 관계를 다시 확인한다. 오른쪽 숫자가 0이면 현재 fetch 기준으로 가져올 원격 전용 커밋이 없으므로 이 원격 추적 브랜치를 추가 병합할 필요가 없다.
로컬 전용 커밋이 없고 원격만 앞선 경우에는 fast-forward만 허용한다.
이 명령이 거절됐다고 강제 옵션을 붙이지 않는다. 다시 커밋 관계를 확인한다.
양쪽에 전용 커밋이 있고 팀 정책상 merge가 맞는 경우에는 다음처럼 병합 커밋 직전에 멈춰 검토할 수 있다.
자동으로 합쳐졌더라도 준비된 변경과 프로젝트 테스트를 확인하고 완료한다.
--no-commit은 fast-forward까지 멈추는 옵션이 아니다. 따라서 위 두 경로는 사전에 확인한 커밋 관계를 기준으로 구분한다. 이 글은 merge 흐름을 설명하며, 팀이 선형 이력과 rebase를 요구하면 해당 정책에 맞는 별도 절차를 따른다. Git merge 공식 문서
5. 실제 merge 충돌은 해결한 경로만 준비한다
목록의 파일을 열어 양쪽 의도를 확인한다. 충돌 표시를 지우는 것만으로 정답이 만들어지는 것은 아니다. 예를 들어 다음 두 설정은 둘 다 줄을 남기는 대신 제품 요구에 맞는 값 하나를 정해야 할 수 있다.
실제 실험에서 사용한 settings.txt를 해결했다고 가정하면 다음 순서다. 다른 저장소에서는 실제 해결한 경로로 바꾼다.
미해결 경로 출력이 없어졌는지 확인한다. diff --check는 공백 오류나 남은 충돌 표시 등을 찾는 보조 검사이며, 프로그램 동작을 검증하는 테스트를 대신하지 않는다. Git diff 공식 문서
병합을 취소하려면 merge가 아직 진행 중일 때 다음 명령을 쓴다.
이미 완료된 병합을 되돌리는 명령은 아니다. 시작 전 미커밋 수정이 있었다면 원상 복원을 항상 보장할 수도 없다. 그래서 먼저 작업을 보관하고 깨끗한 상태에서 시작한다. Git merge의 사전 검사와 abort 설명
6. stash 복원 충돌은 merge 충돌과 종료 방법이 다르다
원격 변경의 통합을 끝낸 후, 앞서 만든 정확한 보관본을 다시 확인한다.
stash@{0}은 다른 stash를 추가하면 달라질 수 있으므로 이름·내용을 대조한다. 여기서는 적용 후에도 보관본이 남는 apply를 썼다. 성공한 pop과 달리 즉시 보관본을 지우지 않아 복원 결과를 먼저 확인할 수 있다.
적용 과정에서 충돌하면 파일을 수정하고 필요한 경로를 git add한 뒤 검토·테스트한다. 이때는 보통 진행 중인 merge 커밋이 없으므로 git merge --continue나 git merge --abort를 해결 명령으로 쓰지 않는다. 복원한 수정이 커밋할 준비가 됐다면 일반 git commit으로 기록한다. Git stash의 apply·pop 설명
작업 내용과 필요한 파일이 모두 복원된 것을 확인한 뒤에만 해당 stash를 삭제한다. 새 stash가 추가됐으면 번호를 다시 확인해야 한다.
7. 임시 저장소에서 실제로 확인한 결과
Git 2.52.0에서 로컬 경로를 원격으로 등록한 격리 저장소를 만들고 세 가지 사례를 실행했다. 다음은 실행 로그의 핵심 결과다.
첫 사례는 미커밋 수정이 원격 변경과 겹쳐 병합이 시작되지 않았고, stash 후 fast-forward는 성공했지만 stash 복원에서 충돌했다. 두 번째는 양쪽 커밋이 같은 줄을 바꿔 실제 merge 충돌이 발생했으며 abort와 수동 해결을 각각 검증했다. 세 번째는 양쪽에 하나씩 커밋이 있어도 서로 다른 경로를 수정하면 충돌 없이 합쳐졌다.
이는 특정 Git 버전의 로컬 재현 결과다. 실제 서비스의 branch protection, 서브모듈, Git LFS, 사용자별 훅·merge driver, 애플리케이션 테스트 결과까지 검증한 것은 아니다.
마지막으로 확인할 것
통합과 필요한 커밋을 마친 뒤 git status, 변경 이력, 프로젝트 테스트를 확인한다. 그 사이 다른 사람이 원격을 갱신해 push가 non-fast-forward로 거절되면 다시 fetch하고 비교·통합한다. 이 상황을 없애려고 바로 force push를 하면 다른 사람의 이력을 덮을 수 있다. Git push 공식 문서
핵심은 ‘머지 명령 하나’보다 작업 보존 → 원격 상태 확인 → 통합 → 충돌 종류에 맞는 마무리 → 검증이다. 특히 백업 브랜치가 미커밋 수정을 보관하지 않는다는 점과 stash 충돌이 진행 중인 merge는 아니라는 점을 구분하면 복구 과정에서 새로운 손실을 만드는 일을 줄일 수 있다.