While many git integration plugins exists, all I simply wanted was a way to view git log interactively inside vim, nothing more.
The following is what I have ended up on, put it into your ~/.bashrc
and
simply run glo
. Press K on top of a commit to view it,
q to quit the buffer and Q to quit vim althogether.
glo() {
git rev-parse 2> /dev/null || return 1
local git_cmd="git --no-pager log --oneline --color=always ${@:--n 128}"
vim \
'+nnoremap q :bd!<CR>' '+nnoremap Q :qa!<CR>' \
"+nnoremap <silent> K 0:tabnew \| setfiletype git \| exe 'read! git --no-pager show <C-r><C-w>' \| norm ggdd<CR>" \
"+call term_start('$git_cmd', {'hidden': 1, 'term_cols': 2048, 'term_finish': 'open', 'term_opencmd': 'buffer %d'})"
}
If you're on neovim, change the entire last line from
"+call term_start...
to just "+term $git_cmd"
.
Everything else remains the same.
Let's start simple. Run git log | vim -
and press K on
top of a commit id. This will show you the commit diff in a terminal. There's
a couple different problems with this:
git log --oneline
"+nnoremap <silent> K 0:tabnew \| setfiletype git \| exe 'read! git --no-pager show <C-r><C-w>' \| norm ggdd<CR>"
Here we are remapping K to:
0
: go to the beginning of the line. With
--oneline
this basically takes the cursor to the commit id.:tabnew
: open a new tab.setfiletype git
: optional, will enable syntax/diff colors.read! git --no-pager show
: this means we want to insert the
output of the given command into our current buffer.<C-r><C-w>
: this is a keybinding to insert
whatever was under your cursor. In our case, the commit id.norm ggdd<CR>
: is just to take the cursor back to the top,
and delete the (empty) line.Since we cannot use |
after a read
command, we're
wrapping the read
into an exe
.
Now you can simply run
git log --oneline -n 128 | vim "+nnoremap <silent> K 0:tabnew \| setfiletype git \| exe 'read! git --no-pager show <C-r><C-w>' \| norm ggdd<CR>" -
and press K to open a commit. This will work on both vim and neovim.
This is already good enough and functional. But we don't have colors on our git log. Vim cannot parse ansi color escape sequence, so we cannot pipe the colored output into vim. However we can just open the git log inside a vim terminal buffer to get around this.
"+term ++curwin git --no-pager log --oneline --color=always"
On neovim remove ++curwin
and you're basically done. But on vim, there's one
more problem; the cursor will be on the bottom of the buffer instead of top. We
can append --reverse
to the git log command to fix this. But a proper
solution is this:
"+call term_start('$git_cmd', {'hidden': 1, 'term_cols': 2048, 'term_finish': 'open', 'term_opencmd': 'buffer %d'})"
What this is doing is running our git command in a hidden terminal buffer, and once that's done, opening that buffer. This prevents the cursor from going down to the bottom.
'+nnoremap q :bd!<CR>' '+nnoremap Q :qa!<CR>'
These are just some quality of life bindings. q to delete the buffer and Q to close vim entirely.
git rev-parse 2> /dev/null || return 1
On top of the shell function, this basically ensures that we're inside a git repo before doing anything. If we're not on a git repo then return early so we don't get a vim buffer with a git error message.
local git_cmd="git --no-pager log --oneline --color=always ${@:--n 128}"
This should be self explanatory. ${@:--n 128}
at the end makes
it so it defaults to showing only 128 commits if no arguments have been given
to the function. Increase/decrease or remove this if you wish. But if you
remove this, do be careful on running this command on large git repos with
thousands of commits.
I think that takes care of everything.
Tags: [ cli ]