While this is certainly doable in vanilla vim
, I suggest you take a look at tpope's excellent vim-fugitive
plugin. Then, you simply need to do :tab Gdiff
to get what you want.
If you really don't want to install any plug-ins, the following might work assuming the current file is in buffer no. 1:
:tabnew | r! git show HEAD^:$(git rev-parse --show-prefix)#1:t
- In the newly opened tab,
:vert sb 1 | windo diffthis
Explanation
- first opens a new tab with
tabnew
and loads the contents of the HEAD^
version of the file in buffer 1 into it.
- opens a vertical split containing buffer 1 with
vert sb 1
, then issues :diffthis
to all buffers in the tab to enter diff mode.
Edit
The OP asked for some more explanation on step 1.
git show
needs an input of the form <rev>:<path>
where <path>
has to be relative to the root of the working tree. For example, if the absolute path of the file in buffer 1 is /a/b/foo.ext
so that b
contains your .git
folder (i.e. b
is the root of your repo), in order for git show
to work properly you would have to invoke it with HEAD^:b/foo.e
. Using either /a/b/foo.ext
or foo.ext
won't work. So I used git rev-parse --show-prefix
to obtain the path of the current folder relative to the git root (which would be b/
) in this example.
Then, I used vim
path expansion to append the name of the file (that is foo.ext
). #1
tells vim
to fetch the path of whatever file is loaded in buffer 1, and :t
extracts the "tail", which is everything after the last /
in the path returned by #1
. In some cases #1
and #1:t
are equal, but this is not always the case. For instance, if you ran vim b/foo.ext
then #1
would return b/foo.ext
instead of just foo.ext
.
Check out :help expand
for more info.
Of course, you could just enter the path manually, as in :tabnew | r! git show HEAD^:b/foo.ext
, and it would work. But the version above is scriptable or you can assign to a map.