TL;DR
- Two approaches: Use VS Code's built-in 3-way merge editor (modern, recommended) or configure it as an external
mergetool/difftoolvia git config - The critical flag: Always pass
--waitwhen callingcodefrom git. Without it, git closes immediately and marks conflicts as resolved - Built-in editor: Enable with
"git.mergeEditor": truein VS Code'ssettings.json. No git config changes needed - External tool: Configure with
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'for terminal-driven workflows
What You'll Learn
- The difference between VS Code's built-in merge editor and configuring it as an external git tool
- Step-by-step configuration for both approaches on Windows and macOS
- How the
--waitflag works and why skipping it breaks your workflow - Advanced configuration options including diff algorithm tuning and workspace settings
- How to troubleshoot the most common setup problems
The Problem
You already live in VS Code. When a merge conflict hits, the last thing you want is to context-switch into a separate tool like Meld or KDiff3 just to resolve it. VS Code has had strong merge and diff capabilities for years. Since version 1.69 (mid-2022), it ships a genuine 3-way merge editor that rivals dedicated tools.
The setup isn't obvious, though. There are two distinct approaches, they work differently, and most guides conflate them. Getting the --wait flag wrong means git treats every conflict as resolved the moment VS Code opens.
Common Questions This Article Answers:
- Do I need to configure git at all, or does VS Code handle it automatically?
- What is the
--waitflag and why does my workflow break without it? - What's the difference between the built-in merge editor and using
codeas an external tool? - How do I use
git difftoolwith VS Code from the terminal? - Which approach should I use for a team environment?
Quick Answer
For the built-in merge editor (recommended): Add one line to VS Code's settings.json:
{
"git.mergeEditor": true
}
For external tool configuration via git config:
# Set VS Code as the merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
# Set VS Code as the diff tool
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'
Then trigger them with git mergetool and git difftool.
Complete Setup Guide
1. Verify the VS Code CLI is Available
Before configuring anything, confirm the code command is available in your terminal. This is the foundation for the external tool approach and required for both workflows.
macOS
# Check if code is already available
code --version
# If not found, install from VS Code:
# Open VS Code → Command Palette (Cmd+Shift+P)
# Type: "Shell Command: Install 'code' command in PATH"
# Click the option — it installs to /usr/local/bin/code
Windows
# Check if code is available
code --version
# If not found, reinstall VS Code and tick:
# ✅ "Add to PATH (available after restart)"
# During installation under "Other" options
# Or add manually — default install location:
# C:\Users\<username>\AppData\Local\Programs\Microsoft VS Code\bin
# Add that path to your user PATH environment variable
Verify it works
# Should print something like: 1.89.0, abc123def, x64
code --version
# The --wait flag test (a dry run — Ctrl+C immediately)
code --wait --new-window
2. Approach 1: Built-in Merge Editor (Recommended)
VS Code 1.69 introduced a dedicated 3-way merge editor. This is the modern approach. It opens automatically when you open a file with merge conflict markers. No terminal command required.
Enable it in settings.json
Open VS Code settings (Cmd+, on macOS, Ctrl+, on Windows), switch to JSON view, and add:
{
"git.mergeEditor": true
}
Or open the Command Palette and search "Open User Settings (JSON)", then add the line.
What you get
Once enabled, when you open a conflicted file (from Source Control panel or terminal), VS Code shows a split 3-pane editor:
- Top-left: Current changes (LOCAL, your branch)
- Top-right: Incoming changes (REMOTE, the branch being merged in)
- Bottom: Result pane: the file you edit and save
Each conflict block has Accept Incoming, Accept Current, and Accept Both buttons. You can also edit the result pane directly for custom resolutions.
Workflow with the built-in editor
# Start a merge that produces conflicts
git merge feature-branch
# CONFLICT (content): Merge conflict in src/auth.js
# Open VS Code (if not already open)
code .
# In the Source Control panel, conflicted files are marked with a C
# Click the file — the 3-way merge editor opens automatically
# Resolve each conflict, then click "Complete Merge" in the editor toolbar
# Back in terminal, stage and commit
git add src/auth.js
git commit
Disable the prompt for each file
By default, VS Code asks whether to open the merge editor or the inline diff view for each conflict. To always use the merge editor without being asked:
{
"git.mergeEditor": true,
"merge-conflict.autoNavigateNextConflict.enabled": true
}
3. Approach 2: External mergetool and difftool via git config
This approach lets you drive conflict resolution entirely from the terminal. You run git mergetool and git opens VS Code for each conflicted file. Same pattern as using Meld or KDiff3, just with code as the binary.
Configure VS Code as mergetool
# Register VS Code as a named merge tool
git config --global merge.tool vscode
# Tell git what command to run
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
# Suppress the "are you sure?" prompt before each file
git config --global mergetool.prompt false
# Clean up .orig backup files after successful merge
git config --global mergetool.keepBackup false
Configure VS Code as difftool
# Register VS Code as a named diff tool
git config --global diff.tool vscode
# The --diff flag opens VS Code's native two-pane diff view
git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'
Why --wait is non-negotiable
When git runs an external mergetool, it needs to know when you've finished editing the file. It does this by waiting for the process to exit. Without --wait, the code command returns immediately after handing off to the VS Code server process. Git sees a zero exit code, assumes the conflict is resolved, and moves on. Every conflict gets silently marked as done whether you touched it or not.
With --wait, the code process blocks until you close the tab or window in VS Code. Only then does git continue.
# Wrong — git won't wait, conflicts get skipped
git config --global mergetool.vscode.cmd 'code "$MERGED"'
# Correct — git blocks until you close the file in VS Code
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
Project-specific configuration
For repositories where you want different tool settings:
# Run from inside the repository (no --global)
cd your-project
git config merge.tool vscode
git config mergetool.vscode.cmd 'code --wait "$MERGED"'
git config diff.tool vscode
git config difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'
4. Usage Examples: Mergetool and Difftool Workflows
Resolving merge conflicts from the terminal
# Trigger a merge that produces conflicts
git merge feature-branch
# CONFLICT (content): Merge conflict in src/api.js
# CONFLICT (content): Merge conflict in src/utils.js
# Launch VS Code for each conflicted file sequentially
git mergetool
# VS Code opens with src/api.js
# Resolve the conflict, save the file, close the tab
# VS Code opens with src/utils.js
# Resolve, save, close
# git mergetool exits
# Commit the result
git commit
Running difftool for code review
# Diff unstaged changes (working directory vs index)
git difftool
# Diff two commits — VS Code opens for each changed file
git difftool HEAD~1 HEAD
# Diff branches
git difftool main feature-branch
# Diff a specific file across commits
git difftool HEAD~3 HEAD -- src/payments.js
# Compare staged changes (what you're about to commit)
git difftool --cached
# Directory diff — opens all changed files at once
git difftool --dir-diff main feature-branch
Advanced Configuration
Custom diff algorithm
The default git diff algorithm produces noisier output than necessary for some refactors. The patience or histogram algorithms group semantically related blocks more cleanly:
# patience works well for most refactoring scenarios
git config --global diff.algorithm patience
# histogram is patience's successor — handles repeated elements better
git config --global diff.algorithm histogram
# Also enable rename detection so moved files diff cleanly
git config --global diff.renames true
git config --global diff.renameLimit 200
Workspace-level settings in VS Code
For team repos, commit a .vscode/settings.json so everyone gets consistent merge editor behavior:
{
"git.mergeEditor": true,
"merge-conflict.autoNavigateNextConflict.enabled": true,
"diffEditor.ignoreTrimWhitespace": false,
"diffEditor.renderSideBySide": true,
"diffEditor.hideUnchangedRegions.enabled": true
}
hideUnchangedRegions.enabled collapses unchanged sections in the diff editor, useful for large files where conflicts are buried.
Show the common ancestor (diff3 style)
When a conflict is ambiguous, seeing the original shared ancestor helps. Enable diff3 conflict style:
git config --global merge.conflictStyle diff3
VS Code's built-in merge editor shows all three versions (LOCAL, BASE, REMOTE) in the top panels when diff3 is active, giving you the full picture for every conflict.
Trust exit code
By default, git asks you after each mergetool session whether the merge was successful. If you want git to trust VS Code's exit code instead:
git config --global mergetool.vscode.trustExitCode true
Note: VS Code exits with 0 even if you close without saving, so this setting can cause false positives. Leave it off unless you have a specific reason.
Team configuration script
For onboarding new developers or standardising across a team:
#!/bin/bash
# setup-vscode-git-tools.sh
echo "Configuring VS Code as Git merge and diff tool..."
# Check VS Code CLI is available
if ! command -v code &> /dev/null; then
echo "ERROR: 'code' command not found."
echo "Install VS Code and enable the 'code' CLI:"
echo " macOS: Command Palette → Shell Command: Install 'code' command in PATH"
echo " Windows: Re-run the VS Code installer and tick 'Add to PATH'"
exit 1
fi
echo "VS Code found: $(code --version | head -1)"
# Configure merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
git config --global mergetool.prompt false
git config --global mergetool.keepBackup false
# Configure diff tool
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'
git config --global difftool.prompt false
# Diff quality settings
git config --global diff.algorithm histogram
git config --global diff.renames true
git config --global merge.conflictStyle diff3
echo "Done. Test with: git difftool --tool-help"
Troubleshooting Common Issues
code not recognized as a command
# Error: bash: code: command not found
# or: 'code' is not recognized as an internal or external command
# macOS fix — install the shell command from within VS Code:
# Command Palette (Cmd+Shift+P) → "Shell Command: Install 'code' command in PATH"
# Then reload your shell
source ~/.zshrc # zsh
source ~/.bashrc # bash
# Windows fix — find the bin directory and add it to PATH:
# Default: C:\Users\<user>\AppData\Local\Programs\Microsoft VS Code\bin
# System Properties → Environment Variables → Path → Edit → New → paste path
# Open a new terminal window after saving
# Verify
code --version
git mergetool exits immediately: conflicts not resolved
This is the --wait flag issue. Confirm your config includes it:
# Check current mergetool command
git config --get mergetool.vscode.cmd
# Should print: code --wait "$MERGED"
# If it's missing --wait, fix it
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
Also confirm you're closing the tab in VS Code, not just switching away. The --wait process holds until the specific tab is closed. The window staying open doesn't release it.
The built-in merge editor isn't opening: shows inline diff instead
VS Code shows inline conflict markers by default unless git.mergeEditor is set. Confirm it's in your user settings, not just workspace settings:
# Check VS Code user settings file
# macOS:
cat "$HOME/Library/Application Support/Code/User/settings.json" | grep mergeEditor
# Windows (PowerShell):
Get-Content "$env:APPDATA\Code\User\settings.json" | Select-String "mergeEditor"
If it's absent, open VS Code settings (Cmd+,) and search for git.mergeEditor. Toggle it on.
Verify your current configuration
# View all merge/diff tool settings at once
git config --list | grep -E "(merge|diff)tool|merge\.tool|diff\.tool"
# Individual checks
git config --get merge.tool
git config --get mergetool.vscode.cmd
git config --get diff.tool
git config --get difftool.vscode.cmd
# List all available tools git knows about
git mergetool --tool-help
git difftool --tool-help
Reset and reconfigure from scratch
# Remove existing VS Code tool configuration
git config --global --unset merge.tool
git config --global --unset mergetool.vscode.cmd
git config --global --unset diff.tool
git config --global --unset difftool.vscode.cmd
# Reconfigure cleanly
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'
VS Code opens but shows an empty file
This usually happens when git can't write the temporary merge file to the expected path, common on Windows with certain repo locations or antivirus interference.
# Check where git writes temp files
echo $TMPDIR
# Try a fresh clone in a clean path (avoid paths with spaces or special chars)
# Temporarily disable real-time antivirus scanning on the repo directory
VS Code vs Dedicated Merge Tools
VS Code handles most conflict resolution well. Here's where it stands against the alternatives:
# Git Visual Tool Comparison
tools:
vscode_builtin:
approach: "Built-in editor (git.mergeEditor: true)"
pros:
- "No additional install — already there"
- "3-way editor since v1.69 (mid-2022)"
- "Same editor for code and conflicts"
- "Extension ecosystem (GitLens etc.)"
- "Cross-platform, free"
cons:
- "Less powerful for highly complex merges"
- "No directory diff mode in the merge editor"
best_for: "Most developers, everyday conflict resolution"
vscode_external:
approach: "External tool via git config (code --wait)"
pros:
- "Terminal-driven workflow — git mergetool"
- "Works consistently with scripts and CI helpers"
- "Same VS Code instance, familiar env"
cons:
- "Requires --wait flag and code in PATH"
- "One file at a time, no batch view"
best_for: "Developers who work from the terminal"
meld:
pros:
- "Excellent 3-pane merge view"
- "Directory comparison built-in"
- "Lightweight, purpose-built"
cons:
- "Separate install and context switch"
- "Windows install path quirks"
best_for: "Cross-platform teams, directory-level diffing"
kdiff3:
pros:
- "Powerful auto-merge engine"
- "Handles complex 3-way conflicts well"
cons:
- "Dated interface"
- "Steep learning curve"
best_for: "Advanced users, complex legacy codebases"
beyond_compare:
cost: "$60 per license"
pros:
- "Best-in-class diff interface"
- "Wide file format support"
- "Folder synchronisation"
best_for: "Professional teams, mixed file types"
Practical guidance: If you're already in VS Code, use it. The built-in merge editor handles the vast majority of day-to-day conflicts without any friction. Reach for Meld or Beyond Compare when you need directory-level diffs across a large changeset, or when you're resolving conflicts in files that VS Code doesn't understand well (certain binary formats, large generated files).
Frequently Asked Questions
Q: Do I need to configure git at all to use VS Code for merge conflicts?
A: Not for the built-in merge editor. If "git.mergeEditor": true is set in VS Code, it intercepts conflict files automatically when you open them from the Source Control panel. No git config changes required. The git config approach (mergetool.vscode.cmd) is only needed if you want to run git mergetool from the terminal and have git explicitly launch VS Code for each conflicted file.
Q: What exactly happens if I forget the --wait flag?
A: Git runs your mergetool.cmd, which calls code $MERGED. VS Code opens the file, but the code process hands off to the running VS Code server and exits immediately with code 0. Git sees a zero exit and interprets it as "conflict resolved successfully." It marks the file as merged and moves to the next one. Your conflicts are still in the file; git just doesn't know that. You end up committing files with raw conflict markers (<<<<<<, =======, >>>>>>>), which typically breaks your build.
Q: Can I use VS Code for both mergetool and difftool at the same time?
A: Yes. The merge.tool and diff.tool settings are independent. You can set both to vscode, or mix them: for example, merge.tool vscode and diff.tool meld. Many developers use VS Code for merges (where the built-in 3-way editor shines) and a separate tool like Meld for directory-level diffs where the side-by-side folder view is more useful.
Q: How do I configure VS Code's own built-in git to use the merge editor, rather than the inline conflict view?
A: Set "git.mergeEditor": true in your VS Code settings.json. The inline conflict view (with inline <<<<<< markers and the Accept Current/Accept Incoming CodeLens buttons) is the fallback when git.mergeEditor is false or absent. The merge editor provides a proper 3-panel view with a dedicated result pane and is generally much easier to use for non-trivial conflicts.
Q: Will this work the same way on Windows and macOS?
A: The git config commands are identical on both platforms. The only platform-specific step is getting code into your PATH. On macOS, VS Code's installer doesn't do this automatically. You must run the shell command install from the VS Code Command Palette. On Windows, the installer offers a checkbox during setup; if you missed it, add the bin directory inside the VS Code install folder to your PATH manually.
Q: Can I configure different settings for specific repositories?
A: Yes. Run the git config commands without --global from inside the repository:
cd your-project
git config merge.tool vscode
git config mergetool.vscode.cmd 'code --wait "$MERGED"'
These settings go into .git/config and override global settings for that repo. You can also commit a .vscode/settings.json file to control VS Code's merge editor behaviour at the workspace level for everyone who opens the repo.
Key Takeaways
- Two distinct approaches:
git.mergeEditor: truein VS Code settings (built-in, no git config needed) vs. configuring VS Code as an externalmergetool/difftoolvia git config (terminal-driven) - The
--waitflag is critical: Without--waitin yourmergetool.cmd, git won't wait for you to resolve conflicts. It marks everything as done immediately codemust be in PATH: Both approaches require thecodeCLI to be accessible; install it from VS Code's Command Palette on macOS, or tick the installer option on Windows- 3-way merge editor since v1.69: VS Code's built-in merge editor is genuinely capable. It shows LOCAL, REMOTE, and a result pane, with per-conflict accept buttons
- Mix tools if needed:
merge.toolanddiff.toolare independent. Use VS Code for conflict resolution and a dedicated tool like Meld for directory-level diffs
What's Next?
If you're on Windows and need a dedicated visual diff tool alongside VS Code, the companion guide walks through the full setup:
- How to Configure Meld as Git Merge and Diff Tool on Windows: step-by-step Meld installation, git config commands, and troubleshooting for Windows path issues
For understanding when to use mergetool vs difftool and how they fit into a broader git workflow, these are worth reading next:
- Git mergetool documentation: official reference for all mergetool options
- Git difftool documentation: flags, dir-diff mode, and tool configuration reference
Resources & References
- VS Code Version Control documentation: official VS Code git integration guide
- VS Code 3-way Merge Editor announcement (v1.69): release notes for the merge editor introduction
- git-mergetool man page: full reference for
git mergetoolflags and tool configuration - git-difftool man page: full reference for
git difftoolincluding--dir-diff - git-config mergetool reference: full list of mergetool config keys
- How to Configure Meld as Git Merge and Diff Tool on Windows: if you need a dedicated external tool for complex diffs
About This Guide: Covers VS Code's built-in merge editor (introduced v1.69) and external mergetool/difftool configuration. Tested on VS Code 1.89+ with Git 2.39+. Last updated May 2026.
Tags: #git #vscode #development-tools #configuration #merge-conflicts