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 충돌을 해결하며 정리한 것이다.

NeovimGitmergetool충돌 해결diffget