Neovim으로 Git 3-Way Merge 충돌 해결하기
git pull에서 divergent branches 오류가 났을 때 Neovim을 mergetool로 등록해 3-way merge로 충돌을 해결하는 실무 절차
2026-08-12 · 최초 발행 2026-04-22
git pull 중에 이런 메시지를 만날 때가 있다.
fatal: Need to specify how to reconcile divergent branches.
로컬 브랜치와 원격 브랜치가 각각 독립적으로 커밋이 진행돼 단순 fast-forward가 불가능한 상태다. pull.rebase false 전략(merge 방식)으로 두 히스토리를 병합하고, 충돌은 Neovim 3-way merge로 해결하는 절차를 정리한다.
Git 설정 (pull.rebase false)
프로젝트 단위로 설정하는 걸 권장한다.
git config pull.rebase false
전역으로 설정하려면:
git config --global pull.rebase false
Neovim을 mergetool로 등록하는 것도 이 단계에서 같이 해둔다.
# ~/.gitconfig 또는 프로젝트 .git/config
git config merge.tool nvimdiff
git config mergetool.nvimdiff.cmd 'nvim -d "$LOCAL" "$REMOTE" "$MERGED" -c "wincmd J | wincmd ="'
git config mergetool.keepBackup false
BASE까지 포함한 더 완전한 3-way merge가 필요하면 nvimdiff4를 쓴다.
git config mergetool.nvimdiff4.cmd 'nvim -d "$LOCAL" "$BASE" "$REMOTE" "$MERGED" -c "wincmd J | wincmd ="'
git config merge.tool nvimdiff4
Pull 재시도 및 merge 실행
# pull.rebase false 설정 후 다시 pull
git pull
# 충돌 파일 확인
git status
충돌이 있으면 이런 출력이 나온다.
CONFLICT (content): Merge conflict in path/to/file.md
Automatic merge failed; fix conflicts and then commit the result.
Neovim mergetool 실행
# 충돌 파일 하나씩 mergetool 실행
git mergetool
# 특정 파일만 실행
git mergetool path/to/file.md
Neovim 3-way merge 화면 이해
실행하면 Neovim이 4-pane 레이아웃으로 열린다.
┌──────────────┬──────────────┬──────────────┐
│ LOCAL │ BASE │ REMOTE │
│ (내 로컬변경) │ (공통 조상) │ (원격 변경) │
├──────────────┴──────────────┴──────────────┤
│ MERGED │
│ (최종 결과 파일) │
└────────────────────────────────────────────┘
각 버퍼가 뭘 의미하는지 표로 정리하면 다음과 같다.
| 버퍼 | 의미 |
|---|---|
| LOCAL | 내 로컬 커밋 내용 (//2) |
| BASE | 두 브랜치의 공통 조상 (//1) |
| REMOTE | 원격(origin)에서 가져온 내용 (//3) |
| MERGED | 실제 편집하고 저장할 최종 파일 |
Neovim 핵심 명령어
충돌 블록 사이를 이동할 때는 ]c(다음), [c(이전)를 쓴다.
| 명령 | 동작 |
|---|---|
]c |
다음 충돌 블록으로 이동 |
[c |
이전 충돌 블록으로 이동 |
MERGED 버퍼에서 어느 쪽 변경사항을 가져올지는 :diffget으로 결정한다.
" LOCAL 변경사항 수락 (내 것 선택)
:diffget LOCAL
:diffget //2
" REMOTE 변경사항 수락 (원격 것 선택)
:diffget REMOTE
:diffget //3
" BASE 기준으로 되돌리기
:diffget BASE
:diffget //1
매번 타이핑하기 번거로우면 단축 커맨드를 등록해두는 게 낫다.
-- init.lua
vim.keymap.set('n', '<leader>gl', ':diffget LOCAL<CR>', { desc = 'Accept LOCAL' })
vim.keymap.set('n', '<leader>gr', ':diffget REMOTE<CR>', { desc = 'Accept REMOTE' })
vim.keymap.set('n', '<leader>gb', ':diffget BASE<CR>', { desc = 'Accept BASE' })
" init.vim
nnoremap <leader>gl :diffget LOCAL<CR>
nnoremap <leader>gr :diffget REMOTE<CR>
nnoremap <leader>gb :diffget BASE<CR>
창 사이를 이동하거나 버퍼 목록을 확인하는 명령도 자주 쓴다.
| 명령 | 동작 |
|---|---|
Ctrl-w h/j/k/l |
좌/하/상/우 창 이동 |
Ctrl-w w |
다음 창으로 순환 이동 |
:ls
충돌 해결 워크플로우
git이 자동으로 삽입한 충돌 마커(<<<, ===, >>>)가 MERGED 버퍼에 그대로 보인다.
<<<<<<< HEAD (LOCAL)
로컬에서 변경한 내용
=======
원격에서 변경한 내용
>>>>>>> origin/master (REMOTE)
여기서부터는 세 가지 방식 중 하나를 고르면 된다.
한쪽 변경사항을 통째로 수락하려면 MERGED 버퍼(하단)로 이동해 충돌 위치에서 :diffget을 실행한다.
" MERGED 버퍼(하단)로 이동 후 충돌 위치에서
:diffget LOCAL " 내 것 선택
:diffget REMOTE " 원격 것 선택
양쪽 내용을 조합해야 하면 MERGED 버퍼를 직접 편집한다. 충돌 마커(<<<<, ====, >>>>)를 지우고, 필요한 내용만 남기거나 양쪽을 합쳐서 정리하면 된다.
파일 전체를 한쪽으로 밀어버리고 싶을 때는 범위 지정 없이 %diffget을 쓴다.
" MERGED 버퍼에서
:%diffget LOCAL " 전체 파일을 LOCAL로
:%diffget REMOTE " 전체 파일을 REMOTE로
저장 및 완료
모든 파일을 저장하고 한 번에 종료하려면:
:wqa
파일별로 확인하면서 저장하고 싶으면 MERGED 버퍼만 저장하고 나머지 읽기전용 버퍼는 종료한다.
" MERGED 버퍼만 저장
:w
" 나머지 읽기전용 버퍼 종료
:qa
Merge 완료
mergetool을 종료한 뒤에는 평소 Git 워크플로우와 동일하다.
# mergetool 종료 후
git status
# 충돌 해결된 파일 스테이징
git add path/to/resolved-file.md
# 모든 충돌 해결 확인 후 commit
git commit
# 기본 merge commit 메시지 자동 생성됨 (저장 후 종료)
# 원격에 push
git push
플러그인 활용 (선택)
fugitive.vim을 쓴다면 mergetool 대신 fugitive의 3-way merge를 쓸 수 있다.
" 충돌 파일 목록 보기
:Git
" mergetool 대신 fugitive 3-way merge
:Gvdiffsplit!
" 창에서 선택
:diffget //2 " LOCAL
:diffget //3 " REMOTE
diffview.nvim이 있으면 파일 히스토리까지 함께 볼 수 있다.
# neovim 내에서
:DiffviewOpen
:DiffviewFileHistory
트러블슈팅
.orig 백업 파일이 계속 남는다면 keepBackup을 꺼두고 기존 파일을 정리한다.
git config --global mergetool.keepBackup false
# 이미 생성된 것 삭제
find . -name "*.orig" -delete
mergetool이 열리지 않을 때는 등록 상태와 nvim 경로를 확인한다.
# 등록된 mergetool 확인
git config --list | grep merge
# nvim 경로 확인
which nvim
충돌 마커가 있는 채로 실수로 저장했다면 검색으로 찾아서 다시 연다.
# 충돌 마커가 있는 파일 검색
grep -r "<<<<<<" . --include="*.md"
# 해당 파일 다시 열어 수동 수정
nvim path/to/file.md
merge 자체를 중단하고 원래 상태로 되돌리고 싶으면:
git merge --abort
빠른 참조 카드
[상황] git pull → divergent branches 오류
[설정] git config pull.rebase false
git config merge.tool nvimdiff4
[실행] git pull → git mergetool
[Neovim 레이아웃]
LOCAL(//2) | BASE(//1) | REMOTE(//3)
─────────── MERGED(편집대상) ──────────
[핵심 키]
]c / [c : 다음/이전 충돌 이동
:diffget LOCAL : 내 것 선택 (//2)
:diffget REMOTE : 원격 것 선택 (//3)
:wqa : 저장 후 전체 종료
[완료] git add . → git commit → git push
이 절차는 gillilab-insights 리포지토리에서 실제로 divergent branches 충돌을 해결하며 정리한 것이다.