function! Display(commit) windo %d diffoff! wincmd t exe ':silent :0 read !git show '.a:commit.'^:'.t:path exe 'doautocmd filetypedetect BufRead '.t:path wincmd l exe ':silent :0 read !git show '.a:commit.':'.t:path exe 'doautocmd filetypedetect BufRead '.t:path wincmd j exe ':silent :0 read !git log --stat '.a:commit.'^..'.a:commit setfiletype git wincmd t diffthis wincmd l diffthis wincmd j normal gg endfunction function! Goto(pos) let t:current = a:pos if t:current < 0 let t:current = 0 return 0 elseif t:current >= t:total - 1 let t:current = t:total - 2 return 0 endif call Display(t:commits[t:current]) return 1 endfunction function! Move(amount) let t:current = t:current + a:amount call Goto(t:current) endfunction function! Blame() let current = t:commits[t:current] let line = line('.') let output = system('git blame -p -n -L'.line.','.line.' '. \current.' -- '.t:path) let results = split(output) if results[0] == "fatal:" return endif for i in range(len(t:commits)) if t:commits[i] =~ results[0] call Goto(i) break endif endfor wincmd t wincmd l exe ':'.results[1] normal z. wincmd j endfunction function! GetLog() let tmpfile = tempname() exe ':silent :!git log --no-merges --pretty=format:"\%H" '.t:path.' > '.tmpfile let t:commits = readfile(tmpfile) call delete(tmpfile) let t:total = len(t:commits) return t:total endfunction function! ChDir() " Change directory to the one with .git in it and return path to the " current file from there. If you live in this directory and execute git " commands on that path then everything will work. cd %:p:h let dir = finddir('.git', '.;') exe 'cd '.dir.'/..' let path = fnamemodify(@%, ':.') return path endfunction function! TimeLapse() " Open a new tab with a time-lapse view of the file in the current " buffer. let path = ChDir() let here = line('.') tabnew let t:path = path if GetLog() <= 1 tabclose return endif set buftype=nofile new set buftype=nofile wincmd j resize 10 set winfixheight wincmd k vnew set buftype=nofile " The first line in the file is the most recent commit let t:current = 0 call Display(t:commits[t:current]) " Go backwards and forwards one commit windo map :call Move(1) windo map :call Move(-1) " Rewind all the way to the start or end windo map :call Goto(t:total - 2) windo map :call Goto(0) windo map :call Blame() " Go to the top right window (which contains the latest version of the " file) and go back to the line we were on when we opened the time-lapse, " so we can immediately Blame from there which is a common use-case. 2 wincmd w exe ':'.here endfunction