Home / Alt manpages / vimdiff(1)

  • vimdiff(1)
  • User command
  • linux

Compare and Merge Files Safely with vimdiff

You will open two versions of a text file in Vim, find each changed region, copy selected changes in either direction, and save only after checking the result. The workflow is useful for configuration files, scripts and patches where a blind overwrite would be risky.

Allow about fifteen minutes for a first comparison. You need Vim from the vim-common package and two readable text files. The examples use Vim 9.1, package version 2:9.1.0016-1ubuntu7.20 on this system. Your exact highlighting and status messages may differ with Vim settings.

Safety boundary

Vimdiff edits real files when you write them. Make disposable copies first if either input is valuable. No command in this guide needs sudo.

1. Make a recoverable test pair

Work in a temporary directory or a project checkout. This example creates two files under /tmp and leaves the originals untouched elsewhere:

$ workdir=$(mktemp -d)
$ printf '%s\n' 'port=8080' 'colour=blue' 'debug=false' > "$workdir/old.conf"
$ printf '%s\n' 'port=8080' 'colour=green' 'debug=true' > "$workdir/new.conf"
$ diff -u "$workdir/old.conf" "$workdir/new.conf"

The final command should show two changed lines: colour and debug. The temporary directory is disposable, but do not use this pattern with a path that contains files you need to keep unless you have checked the command carefully.

Checkpoint

Confirm the two paths and make a backup before editing a real file:

$ cp --preserve=mode,timestamps /path/to/config.conf /path/to/config.conf.before-vimdiff
$ test -r /path/to/config.conf.before-vimdiff && echo backup-ready
backup-ready

2. Open the files in diff mode

Give the older or trusted file first, then the file you want to inspect. Vim opens one window per file and normally uses vertical splits:

$ vimdiff /path/to/old.conf /path/to/new.conf

Both buffers start in diff mode. Changed text is highlighted, the windows scroll together, and unchanged ranges may be folded. The first file is not automatically treated as the correct answer. It is only the first buffer, so decide the direction of every merge yourself.

For horizontal splits, add -o:

$ vimdiff -o /path/to/old.conf /path/to/new.conf

Vimdiff accepts two to eight files. With more than two, the screen becomes busy quickly; compare a smaller pair when you need to reason about ownership of a change.

To check the installed command without opening a file, use ordinary, read-only commands:

$ command -v vimdiff
/usr/bin/vimdiff
$ vim --version | sed -n '1p'
VIM - Vi IMproved 9.1 (2024 Jan 02)

3. Move between changed regions

Put the cursor in a changed region and use ]c to jump to the next change or [c to jump to the previous one. If folds hide surrounding context, use zO to open the fold under the cursor. Use zo to open one fold and zc to close it again.

The active window matters. Commands that copy a change use the other diff window as their source or destination, so check which pane has the cursor before pressing a merge command.

When you have edited a buffer during the session and the highlighting looks stale, run this command in Vim's command line:

:diffupdate

Use Esc first if you are typing text. A visible change is evidence for inspection, not a decision about which version should win.

4. Copy one change, then inspect it

There are two complementary merge commands:

  • do, short for diff obtain, pulls the change from the other window into the current window.
  • dp, short for diff put, sends the current window's change to the other window.

Place the cursor inside the desired change, press do or dp, then read both windows again. These commands alter Vim buffers immediately. They do not write the files until you use a write command.

For a deliberate command-line version, use :diffget to obtain a change or :diffput to put it. A count or buffer argument can matter when more than two windows are open, so use the normal cursor-based command for a two-file comparison until you are comfortable with the layout.

Recovery

Before saving, u undoes the most recent buffer change and CTRL-R redoes it. If you are no longer confident about the buffer, close Vim with :q! for the current window, or :qa! for all windows. The exclamation mark discards unsaved edits, so use it only after checking that you do not need them.

5. Save only the intended buffer

When the merged text is correct, write the current buffer with:

:write

In a two-file session, write each accepted result separately. Use CTRL-W w to move to the other window, inspect it, and write it only if that file should also change. :w and :write are equivalent.

Do not use :w! as a reflex. It can override a read-only safeguard or permission check. If Vim refuses to write, stop and establish why the file is read-only or owned by another account. Changing ownership or permissions is outside this comparison workflow and may need an administrator's decision.

Quit after checking the status line or saving message:

:qa

If Vim reports unsaved changes, do not add ! until you have decided whether to save or discard them.

6. Verify outside Vim

Use a separate command to confirm the resulting file contains what you intended. For a pair where new.conf is the accepted target, this should produce no output:

$ diff -u /path/to/new.conf /path/to/new.conf
$ printf 'exit status: %s\n' "$?"
exit status: 0

That self-comparison only checks that the path is readable. A useful verification compares the edited file with the backup or with the source you meant to reproduce:

$ diff -u /path/to/config.conf.before-vimdiff /path/to/config.conf
$ grep -nE '^(port|colour|debug)=' /path/to/config.conf

Review every reported hunk. A zero exit status from diff means the files are identical; status 1 means they differ; a higher status usually indicates an error such as a missing or unreadable path.

Done means

  • You opened the intended files and checked their order before merging.
  • You navigated to changes and chose do or dp per hunk.
  • You know unsaved changes can be undone with u or discarded with :q!.
  • You wrote only the buffer that should change, without using :w! blindly.
  • You verified the saved file with an external command and kept a recovery copy where needed.