Showing Git diff in Vim

The usual method of viewing the diff of the current file against the HEAD of the repository is to first exit vim, run git diff <current-file>, view the diff, and resume vim again. This is tedious. There must be a better way to view the git diff without needing to exit vim. One way to solve this problem is to define a simple function along with a keybinding to show the diff within vim. In this article, I will present a method I use.

A possible solution (meant to be placed in ~/.vimrc):

function GitDiff()
    :silent write
    :silent execute '!git diff --color=always -- ' . expand('%:p') . ' | less --RAW-CONTROL-CHARS'

nnoremap <leader>gd :call GitDiff()<cr>

With this keybinding, pressing leader + g + d while in normal mode shows the git diff using less. You can exit less by pressing q, at which point you will be brought back to the vim buffer you were working on.

How does the GitDiff vim function work? First, it saves the file. Then, git diff for the current file is piped into less, which shows the diff of the current file. expand('%:p') provides the full path to the current file (i.e. the file in the current buffer). --color=always and --RAW-CONTROL-CHARS ensure that coloured output is shown (i.e. green for additions, red for deletions). Then, for technical reasons, the screen is redrawn using :redraw! to display the buffer that you have been working on right before the diff is shown. You can, of course, customize the keybinding to your liking. In the example above, the keybinding for the function is <leader>gd in normal mode (where gd is meant as a mnemonic for git diff).

Simple vim functions and keybindings save lots of time, and reduce the need for context switches that can potentially make you lose focus. I encourage you to take note of the repetitive vim tasks that you have, and try to automate them, or reduce the amount of steps needed to achieve them. The vim keybinding for git diff above is a small and simple workflow improvement that reduces the amount of steps needed to achieve a common task. I hope it helps.