Configuring git mergetool for three-way resolution Jump to heading
Resolving a large conflict in a text editor means scrolling between marker sections and holding three versions in your head. A merge tool lays them out side by side β ours, the base, theirs β with the result below, so you can see each sideβs change against the ancestor and pick or combine hunks with a click. git mergetool launches one for each conflicted file, but out of the box it often picks a tool nobody has installed, leaves .orig backup files everywhere, and opens a two-pane view that hides the base. This page configures it properly for the editors teams actually use, and explains when it is worth reaching for. It belongs to 3-way merge fundamentals.
When to use this approach Jump to heading
- Conflicts regularly span dozens of lines or several hunks in one file.
- You resolve conflicts in files where structure matters β nested configuration, long functions.
- Team members use different editors and want a consistent way to launch resolution.
- For short conflicts, reading markers directly is faster; set up diff3 and zdiff3 conflict markers first either way.
Step 1 β Pick a tool that shows the base Jump to heading
The tool must show the merge base as its own pane, or most of the benefit is lost. Tools differ in layout; the important thing is three inputs plus a result.
# See which tools Git knows how to drive and which are installed
git mergetool --tool-help | sed -n '1,25p' Step 2 β Configure the tool and its command Jump to heading
For tools Git knows, setting merge.tool is enough. For anything else, define mergetool.<name>.cmd using the four variables Git provides.
# VS Code, using its built-in three-way merge editor
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge "$REMOTE" "$LOCAL" "$BASE" "$MERGED"'
# vimdiff with a layout that shows the base (Git 2.37+ supports layout strings)
git config --global merge.tool vimdiff
git config --global mergetool.vimdiff.layout "LOCAL,BASE,REMOTE / MERGED"
# Meld, which Git drives natively
git config --global merge.tool meld Quote the variables in custom commands: paths with spaces otherwise break the command in confusing ways.
# Verification: launch on a conflicted file and confirm four panes appear
git merge feature/x || git mergetool -- path/to/conflicted.file Step 3 β Stop the clutter and the prompts Jump to heading
By default git mergetool writes a .orig backup of each file and asks for confirmation before opening each one. Turn both off; the backup is redundant because the conflicted state is in the index and the reflog.
git config --global mergetool.keepBackup false
git config --global mergetool.prompt false
# Trust the tool's exit code so files are marked resolved only when you save and quit successfully
git config --global mergetool.vscode.trustExitCode true trustExitCode matters: without it Git asks βwas the merge successful?β after each file. With it, closing the tool normally marks the file resolved, and aborting leaves it conflicted.
Step 4 β Resolve, then inspect before committing Jump to heading
The tool writes the result into the working tree and stages it. Before committing, check that no markers remain and that the result does what both sides intended β the tool makes combining hunks easy, which also makes combining them wrongly easy.
git diff --cached --check # flags leftover conflict markers and whitespace errors
git diff --cached # read the result one more time
git grep -nE '^(<{7}|={7}|>{7}|\|{7})( |$)' -- $(git diff --cached --name-only) || echo "no markers" Step 5 β Share a team default without forcing it Jump to heading
Teams benefit from a shared default, but editors are personal. Put a sensible default in a team configuration file included by everyone, as described in shipping a team gitconfig with includeIf, and let individuals override it in their own global configuration.
# team.gitconfig β included by every developer
[merge]
conflictStyle = zdiff3
[mergetool]
keepBackup = false
prompt = false
[mergetool "vscode"]
cmd = code --wait --merge \"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"
trustExitCode = true Leave merge.tool itself unset in the team file, so each person chooses; the per-tool settings are ready whichever they pick.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Can I use mergetool during a rebase? Jump to heading
Yes. During a rebase that stops on a conflict, git mergetool works the same way; remember that during a rebase βlocalβ is the branch you are rebasing onto and βremoteβ is your commit being replayed.
Does a merge tool understand code structure? Jump to heading
Most work line by line, like Git. Some language-aware tools can merge at the syntax level and resolve conflicts like two imports added in the same place. They are worth trying for heavy refactoring work, but review their results carefully.
Why does mergetool say there is nothing to merge? Jump to heading
It only opens files with unresolved conflicts. If you already staged a file with git add, Git considers it resolved. Use git checkout --conflict=zdiff3 -- path to restore the conflict, then run the tool again.
Related Jump to heading
- 3-Way Merge Fundamentals β the parent topic.
- Resolving Complex Binary Conflicts in Git β where text merge tools cannot help.
- Ours and Theirs During Merge vs Rebase β which pane is which in each operation.
- Automating Repeated Conflict Resolution with Rerere β so you only resolve each conflict once.