217

I use Vim as my primary editor.

I would also like to use vim to diff files and modify the files while doing the diff to fix easy changes (rather than most diff techniques which are a cycle of diff, fix, diff, fix).

Additionally are there easy ways to integrate Vim into diff tools used by source control tools/sites?

I am specifically thinking of git but I am sure other people would be interested in integration with other source control tools/sites.

3
  • 3
    you should try vim-fugitive it adds the commands :Gdiff and :Gvdiff both commands lets you see the side by side diff of the current buffer if your current buffer is managed by git. It also heps you to resolve conflicts in a three window layout when you have merge conflicts on some files
    – rbernabe
    Commented Mar 23, 2017 at 4:31
  • I have this simple function in my bashrc vd () { diff $@ > /dev/null ; if [[ $? -eq 1 ]] ; then ; vimdiff -c 'windo set syntax=off' $@ ; fi ; } and I invoke it with vd file1 file2. It uses diff to determine whether the files differ and only opens vimdiff if that is so. Otherwise, I stay in the shell. I also disable syntax highlighting in Vim because I find it distracting when diffing. Only works with two files.
    – Rolf
    Commented Oct 6, 2017 at 6:10
  • @rbernabe is right, Tim Pope's fugitive is a wonderful tool for merges - there's also an equally wonderful Vimcast explaining fugitive. You can setup fugitive as your mergetool - see stackoverflow.com/a/7313949/327074
    – icc97
    Commented Jan 30, 2022 at 10:42

11 Answers 11

221

vim has this functionality built in (with the correct command line flag).

vim -d <file1> <file2>

This opens each file in a view and highlights the differences.
Any code that is identical is folded away so you do not need to look at identical code or scroll through huge chunks of identical code.

But there is also a wrapper application vimdiff that correctly invokes vim with the correct flags.

vimdiff source1.cpp source2.cpp

If you are using git you can set up an external diff tool. So it is easy to set up vimdiff to be the diff tool for git.

git config --global diff.tool vimdiff

When using vimdiff you can edit either side and diff highlighting keeps pace to show you the differences.

Note: When editing from a git diff. If you try and edit the repository stored version of the file your changes will be discarded when you exit (git does not trust you with the original so you are diffing against a tmp copy) but you can edit the local copy to your hearts content and save it over you current version.

Some basic commands that are useful in vimdiff

dp             diffput: puts changes under the cursor into the other file
                        making them identical (thus removing the diff).
do             diffget: (o => obtain). The change under the cursor is replaced
                        by the content of the other file making them identical.


]c             Jump to the next diff
[c             Jump to the previous diff

Other vim settings I use to work with highliting with vimdiff

if &diff
    highlight! link DiffText MatchParen
endif

This turns off highlighting on the bits of code that are changed. So the line that is changed is highlighted so I can spot the changes, but the actual text that has changed stands out on the line (as it is not highlighted).

7
  • 59
    You can also use the :diffthis command to initiate a diff when Vim is already running.
    – Rich
    Commented Feb 10, 2015 at 11:15
  • 18
    And :diffoff to turn it off. I think a link to vim's documentation would be beneficial: vimdoc.sourceforge.net/htmldoc/diff.html
    – Cody Poll
    Commented Feb 12, 2015 at 4:49
  • 2
    For me even after git config --global diff.tool vimdiff, git diff still shows everything like if I change nothing.
    – Hi-Angel
    Commented Sep 1, 2016 at 15:17
  • 4
    try git difftool Commented Sep 1, 2016 at 16:25
  • 1
    There is also :diffupdate which will refresh the diff view after changes: ```` :diffupdate ```` Commented Feb 1, 2019 at 19:24
53

If you are editing an open file and want to compare it to another file without closing the current one:

Open the new file in split screen:

For vertical split:

:vs otherFile

or horizontal split:

:split otherFile

Switch cursors to different split screen:

ctrl+w ctrl+w

Invoke "diff mode" in file:

:diffthis

Switch to other file and invoke "diff mode":

:diffthis

To turn off "diff mode":

:diffoff
3
  • 14
    To avoid switching between the buffers you can use :windo diffthis too
    – statox
    Commented Oct 2, 2018 at 14:50
  • 3
    @statox: works for diffoff as well, so :windo diffthis and :windo diffoff to start and stop diff for two open windows. Or abbreviated :windo difft and diffo!.
    – Wolfson
    Commented Oct 5, 2020 at 13:14
  • 1
    If starting with one open file File1, you can also use :vert diffs File2 to open File2 in a vertical split on the right and diff it with File1.
    – Wolfson
    Commented Oct 5, 2020 at 13:17
7

For NeoVim, you can setup your ~/.gitconfig with the following commands

git config --global merge.tool nvim
git config --global mergetool.keepBackup false
git config --global mergetool.nvim.cmd $'nvim -d $LOCAL $REMOTE $MERGED -c \'$wincmd w\' -c \'wincmd J\''

Your ~/.gitconfig should then look like:

[merge]
    tool = nvim

[mergetool]
    keepBackup = false

[mergetool "nvim"]
    cmd = nvim -d $LOCAL $REMOTE $MERGED -c '$wincmd w' -c 'wincmd J'

Refer to Nvim documentation: diff for more info on how to configure it to your liking.

1
  • Can you explain a bit more about the last command? Is there a Linux alternative? Also worth noting that keeping the .orig file or not (i.e. mergetool.keepbackup is a matter of preference.
    – Colin
    Commented Nov 16, 2021 at 9:04
5

You can place below mentioned setting in .gitconfig file found in %homepath% (or %userprofile%) directory of the currently logged in user:

[diff]
    tool = vimdiff

This will enable git bash tool to start using vimdiff as the external diff tool as well.

1
  • This is the best way
    – Igbanam
    Commented Aug 31, 2023 at 9:26
4

Following is my git config:

https://github.com/tracyone/dotfiles/blob/master/.gitconfig

[core]
editor = vim
[diff]
tool = vimdiff
[merge]
tool = vimdiff
conflictstyle = diff3
[difftool]
prompt = 0
2

I can see only three situations to use vim as a difftool. They are briefly described below:

  • For git difftool, put the following in your ~/.gitconfig:

    [core]
    editor = vim
    [diff]
    tool = vimdiff
    [merge]
    tool = vimdiff
    conflictstyle = diff3
    
  • To open vim as a diff-tool for two file, you can do the following:

    vimdiff file1.ext file2.ext      # for vim
    nvim -d file1.ext file2.ext      # for neovim
    
  • To get diff view for the buffers that are currently active, i.e. all the buffers that have a window assigned to them in the currently active tabpage, you can do the following:

    :windo diffthis                " to get diff view
    :windo diffoff                 " to remove diff view
    

For more information, see :h diff

1
  • 2
    if only one file open yet: :vert diffs File2 to diff with File2.
    – Wolfson
    Commented Oct 6, 2020 at 13:39
2

I think using vscode-neovim to handle git diff is more convenient.

Using the GUI is convenient to compare between branches, commits and so on.

vscode-neovim give you almost the same (or 90%?) experience of original neovim, using most part of its vimrc(init.vim), unlike vscode's vim extension, which is not so "vim"

enter image description here

2
  • 2
    This may not actually answer the question, as vscode is not Vim? The answer also does not provide enough details on how to use Vim as a diff tool (a sentence about your preference and a screenshot are not enough; the answer would benefit from specific steps). You can edit this answer to improve it
    – D. Ben Knoble
    Commented Feb 17, 2022 at 18:18
  • I believe the 3 column diff mode is also present in standard vim. Commented Feb 21, 2022 at 1:19
2
vimdiff file1 file2 

or

vim –d file1 file2

Once in vimdiff mode, use this command for horizontal split :diffsplit and for vertical split :vert diffsplit.

To apply change from adjacent window to current window use :diffget and to apply change from current window to adjacent window use :diffput

1

here's what I do:

  • open a window with first file (or text contents if you're pasting data)
  • open next file/window using :vnew (to have both windows side by side) or :new (to have the windows top and bottom). if you have a specific file to open in the second window, you can include the path like this: :vnew /path/to/secondfile.txt
  • use F8 to toggle a custom function which turns diff mode on and off

here's the custom function that's in my ~/.vimrc:

nmap <silent> <F8> :call ToggleDiff()<CR>
imap <silent> <F8> <C-O>:call ToggleDiff()<CR>
function ToggleDiff ()
    if (&diff)
        set nodiff noscrollbind
    else
        " enable diff options in both windows; balance the sizes, too
        wincmd =
        set diff scrollbind nowrap number
        wincmd w
        set diff scrollbind nowrap number
        wincmd w
    endif
endfunction
1
  • you can use the command :diffthis and diffoff! so you don't have to set all diff options yourself (e.g. cursorbind is also set by diffmode) Commented Apr 17, 2019 at 16:49
0

I have adopted by .vimrc with some useful commands in diff mode (lower part). If you edit in normal mode the setting are reset (upper part). You can copy it simply in your .vimrc file.

nmap <silent> <F2> :exec &nu==&rnu? "se nu!" : "se rnu!"<CR>
inoremap <Esc>Oq 1
inoremap <Esc>Or 2
inoremap <Esc>Os 3
inoremap <Esc>Ot 4
inoremap <Esc>Ou 5
inoremap <Esc>Ov 6
inoremap <Esc>Ow 7
inoremap <Esc>Ox 8
inoremap <Esc>Oy 9
inoremap <Esc>Op 0
inoremap <Esc>On .
inoremap <Esc>OQ /
inoremap <Esc>OR *
inoremap <Esc>Ol +
inoremap <Esc>OS -
inoremap <Esc>OM <Enter>
nnoremap <Esc>OQ B                      "       /
nnoremap <Esc>OR E                      "       *
if &diff
        map <Esc>Oq zc                  "       1       close a fold
        map <Esc>Or <down>              "       2       cursor down
        map <Esc>Os ]c                  "       3       next diff
        nmap <Esc>Ot <left>             "       4       curosor left
        nnoremap <Esc>Ou <c-w>w         "       5       jump to next file
        map <Esc>Ov <right>             "       6       cursor right
        map <Esc>Ow zo                  "       7       open a fold
        map <Esc>Ox <up>                "       8       curosor right
        map <Esc>Oy [c                  "       9       prefious diff
        map <Esc>Op 0                   "       0       0
        nmap <Esc>On .                  "       .       .
        nmap <Esc>OQ B                  "       /       back one word
        nmap <Esc>OR E                  "       *       end of word
        nmap <Esc>Ol dp                 "       -       diffput
        nmap <Esc>OS do                 "       +       diffget
        nmap <Esc>OM :diffupdate        "       Enter
endif

Of course, you can change my settings. If you want to put another command on "0", change the command right after "Op" e.g. with "za" which toggles between fold and unfold:

    nmap <Esc>Op za                   "       0       0

Please be aware of the different use of "map" and "nmap" depending on the key.

0

A variation on the common DiffOrig vim command:

if !exists(":GitDiff")
  command GitDiff set nofoldenable | vert new | set bt=nofile |
    \ let @"=system('git show HEAD~0:' . system('git rev-parse --show-prefix | tr -d "\n"') . expand('#')) | exec "normal PGdd" |
        \ diffthis | wincmd p | diffthis
endif

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.