For a long time now I’ve wanted to have the current diff of my working copy highlighted in vim. This would help a lot when you’re working in complicated code and want your modifications to pop out in case you’ve missed something. Unfortunately none of the existing tools do exactly what I want, so with the advice of some co-workers I’ve hacked up the svndiff vim script and made it work with git just like I wanted. Now I can turn on or refresh the highlights with Ctl-D and diff against a different branch with “:D <branch>”.

gitdiff.vim
—————
if exists(”loaded_gitdiff”) || &cp
finish
endif
let loaded_gitdiff = 1
map <C-d> :call <SID>Gitdiff()<CR>
map <C-g> :set nodiff<CR>
noremap <unique> <script> <plug>Dh :call <SID>Gitdiff(”h”)<CR>
com! -bar -nargs=? D :call s:Gitdiff(<f-args>)
let g:gitdiff_rev = ”
function! s:Gitdiff(…)
if a:0 == 1
if a:1 == “none”
let g:gitdiff_rev = ”
else
let g:gitdiff_rev = a:1
endif
endif
let ftype = &filetype
let tmpfile = tempname()
let cmd = “cat ” . bufname(”%”) . ” > ” . tmpfile
let cmd_output = system(cmd)
let tmpdiff = tempname()
let cmd = “git diff ” . g:gitdiff_rev . ” ” . bufname(”%”) . ” > ” . tmpdiff
let cmd_output = system(cmd)
if v:shell_error && cmd_output != “”
echohl WarningMsg | echon cmd_output
return
endif
let cmd = “patch -R -p0 ” . tmpfile . ” ” . tmpdiff
let cmd_output = system(cmd)
if v:shell_error && cmd_output != “”
echohl WarningMsg | echon cmd_output
return
endif
if exists(”s:killbuffs”)
2,9999 bdelete
endif
let s:killbuffs = 1
if a:0 > 0 && a:1 == “h”
exe “diffsplit” . tmpfile
else
exe “vert diffsplit” . tmpfile
endif
exe “set filetype=” . ftype
hide
set foldcolumn=0
set foldlevel=100
set diffopt= ” removed filler so we don’t show deleted lines
highlight DiffAdd ctermbg=black ctermfg=DarkGreen
highlight DiffChange ctermbg=black ctermfg=DarkGreen
highlight DiffText ctermbg=black ctermfg=DarkGreen cterm=underline
highlight DiffDelete ctermbg=red ctermfg=white
endfunction
“autocmd CursorHold * call s:Gitdiff()
—————
Tags: vimdiff git
26 Responses for "Vim Diff"
This doesn’t work for me. What am I doing wrong?
Error detected while processing /home/james/.vim/plugin/gitdiff.vim:
line 1:
E15: Invalid expression: ”loaded_gitdiff”) || &cp
E116: Invalid arguments for function exists(”loaded_gitdiff”) || &cp
E15: Invalid expression: exists(”loaded_gitdiff”) || &cp
line 11:
E15: Invalid expression: ”
E15: Invalid expression: ”
line 13:
E125: Illegal argument: …)
line 64:
E492: Not an editor command: “autocmd CursorHold * call s:Gitdiff()
Ah, I think the double-quote characters have been mangled by the blog engine you use.
unicode wins again
eh, sorry about that it was a quick cut/paste job. I can post the original file for you and others to download if you like.
Nice. Can you upload the script to http://www.vim.org/login.php?add_script.php ?
A s/git/svn/g makes it work with svn, too. Very slick.
I took the liberty of posting a modified version that allows using any SCM with standardized ’scm diff’ output (svn, git, and Mercurial all work).
http://www.vim.org/scripts/script.php?script_id=2201
Thanks for this, it’s quite useful.
I’d suggest removing those bindings and list them as an example on that page. I actually use Ctrl-G pretty often.
It was easy enough to fix for myself, but not something I’d like to remember to do each time I installed or upgraded the script.
Not to sound ungrateful, Thanks. :)
Happy to see you all found it useful, and thanks for modifying it and uploading it to vim.org! I was hoping to enhance it for SVN but hadn’t gotten to it yet. Hopefully it’ll be useful to a wider range of people now.
Hey,
I took the modified SCMdiff version from vim.org and made even more mods.
You can find my version here:
http://playground.audioscrobbler.com/jonty/scmdiff.vim
It:
- Removes the ctrl-g keybinding and makes ctrl-d a toggle
- Resets the viewport when pressing ctrl-d the first time (no more scrolling, yay!)
- Has indentation ;)
I also camelCased all the vars, as I’m a picky bastard…
Hope that’s useful to you.
Thank you Shire for the original post
and thank you Jonty for the viewport tweaks!
Thanks for a great script!
I had to make a few tweaks to Jonty’s script. Removed this line:
let b:scmDiffOn = 1
and changed this line:
if b:scmDiffOn == 1
to:
if exists(’b:scmDiffOn’) && b:scmDiffOn == 1
Also changed the “map …” to “map “.
Is there any way of getting rid of the “2,9999 bdelete” and the left over buffer? I normally use a lot of buffers and just closing all of them like that is not very nice, IMHO.
Oh noes, my angle brackets were eaten by the interwebs.
Also changed the “map [C-d] …” to “map [silent] [C-d] …”.
Jonas, what?! If you do that you won’t be able to toggle it off again?
Jonas, thanks for the silent tweak, applied to the version I linked above.
Still have no idea what you’re on about with the scmDiffOn var though ;)
Sorry, manual diffs from (lack of) memory aren’t very reliable. There are two “let b:scmDiffOn = 0″ (not “= 1″ as I said before), I removed the first one so there are only two places where it sets that variable. My problem was that for some reason it barfed in s:scmDiff() since that variable wasn’t set (hence the if exists()).
Jonas, aha, now you make sense! Odd that it died for you - what version of vim are you using?
(I’ll fix it in the linked version tomorrow morning)
7.1.138. But it might be due to the fact that I’m normally using multiple buffers, and the plugin is only run once so it won’t set the variable in all buffers, AFAIK.
Aha! That’ll be it, I only tested it in a single buffer instance. More fool me.
Anyone made a version that would work with multiple buffers open (not closing unrelated buffers)? I really like this script, but it’s usually unusable for me when it behaves this way. I’m using MacVim BTW if that’s relevant.
I have posted an updated version at http://github.com/ghewgill/vim-scmdiff/ which avoids the “2,9999 bdelete” problem, among other improvements.
Is there enough interest here to setup an central repro somewhere wiht a few accounts for the ppl here? (github or I can setup something on tekrat.com). That way everyone can commit to one spot?
Has anoyone played with keeping the deleted lines present in some way?
Another change: There’s probably a better way to do this than what I have below but it seems like we should be detecting the SCM automatically as much as possible. Something like this should at least work for detecting git/svn.
diff –git a/scmdiff.vim b/scmdiff.vim
index 4811bcf..042e8cd 100644
— a/scmdiff.vim
+++ b/scmdiff.vim
@@ -1,7 +1,3 @@
-if !exists(”g:scmDiffCommand”)
- let g:scmDiffCommand = ‘git’
-endif
-
if exists(”loadedScmDiff”) || &cp
finish
endif
@@ -36,6 +32,18 @@ endfunction
function! s:scmDiff(…)
+ let cmdOut = system(”git status”)
+ if !exists(”g:scmDiffCommand”) && !v:shell_error
+ let g:scmDiffCommand = ‘git’
+ endif
+ let cmdOut = system(”svn info”)
+ if !exists(”g:scmDiffCommand”) && !v:shell_error
+ let g:scmDiffCommand = ’svn’
+ endif
+ if !exists(”g:scmDiffCommand”)
+ let g:scmDiffCommand = ‘git’
+ endif
+
if exists(’b:scmDiffOn’) && b:scmDiffOn == 1
let b:scmDiffOn = 0
set nodiff
Due to the interest in this the new official home for this code is on GitHub!
per Greg’s previous post:
http://github.com/ghewgill/vim-scmdiff/
Make changes via the GitHub interfaces (fork/pull etc), or email us!
I LOVE THIS!!!
I know I’m late to the party, but I don’t know how I missed this fabulous vim plugin.
I only wish it worked in plain old ‘vi’ which is what I use by habit.
Or maybe I can just append it to .exrc?
I’ll give that a shot.
Anyway, thanks Brian for this “how did I live without it” tool!
Happy you like it Richard, although I’m not sure on vi but good luck! ;-)
Leave a reply