Skip to content

How to Set Up VS Code as Your Git Merge and Diff Tool: Complete Guide

Configure VS Code as your Git merge and diff tool using the built-in merge editor or external mergetool/difftool. Covers --wait flag, 3-way merge editor, and team setup.

TL;DR

  • Two approaches: Use VS Code's built-in 3-way merge editor (modern, recommended) or configure it as an external mergetool/difftool via git config
  • The critical flag: Always pass --wait when calling code from git. Without it, git closes immediately and marks conflicts as resolved
  • Built-in editor: Enable with "git.mergeEditor": true in VS Code's settings.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 --wait flag 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 --wait flag and why does my workflow break without it?
  • What's the difference between the built-in merge editor and using code as an external tool?
  • How do I use git difftool with 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: true in VS Code settings (built-in, no git config needed) vs. configuring VS Code as an external mergetool/difftool via git config (terminal-driven)
  • The --wait flag is critical: Without --wait in your mergetool.cmd, git won't wait for you to resolve conflicts. It marks everything as done immediately
  • code must be in PATH: Both approaches require the code CLI 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.tool and diff.tool are 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:

For understanding when to use mergetool vs difftool and how they fit into a broader git workflow, these are worth reading next:

Resources & References


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