This tweet blew my mind.
$ git log | vim -R –
Now press <K> on a commit hash.
— Luke Diamand (@LukeDiamand) February 21, 2018
I spend a lot of my time in Vim and Git and this is an amazing combination of the two. While I love this command, I think we can do even better (jump to my version).
What is going on?
$ git log | vim -R -
Running this command, executes
git log and opens a copy of Vim populated with the results of
git log. Once you’re in Vim, if you place your cursor over a commit (e.g.
083279917ae3bbe8bfc25b2bf785acbbee302415) and click
K, you’ll be temporarily shown the result of running
git show on the commit.
Why does this work?
When you’re in Vim, the default behavior when you click
K is to take the word under the cursor and look it up using the man program. This behavior can be modified by setting the value of keywordprg to something other than
Vim automatically sets
keywordprg for some filetypes, including the filetype
git. When the filetype is set to
keywordprg is set to
How does Vim know it is Git?
This is a great question that I don’t know the answer to. I’m guessing Vim recognizes the standard format of
Can We Improve This?
I don’t love the standard format for
git log. I have an improved version of git log that I prefer to use. This made me wonder if we can get this same commit view behavior in Vim with a log format I prefer. This is what I came up with.
git log --graph --pretty=format:'%h - %d %s (%cr) <%an>' | vim -R -c 'set filetype=git nowrap' -
Unfortunately, I couldn’t use my improved version of git log as it appears in that article because it includes color values, which muddy up the output in Vim. Instead, I’m using a simplified version.
git log --graph --pretty=format:'%h - %d %s (%cr) <%an>'
Here are the relevant links if you want to read about how this works.
%h– abbreviated commit hash
%d– ref names, like the –decorate option of git-log
%cr– committer date, relative
%an– author name
When I feed my customized
git log output into Vim, Vim fails to set the filetype to
To correct this we include
-c 'set filetype=git'.
We also set nowrap so the lines do not wrap when they are displayed.
-R is used to start in read-only mode.
Notes about Neovim
If you’re using Neovim, you’ll find that when you view a commit you can only see the end of the commit and you can not scroll back up. Instead you see the message “Press ENTER or type command to continue”.
This is due to how Neovim handles bang/system commands, as the author of Neovim, Thiago de Arruda, writes in this comment on Neovim Issue 1496
This is not a bug, it is the new behavior of bang commands: We no longer spawn the program with it’s stdout connected to Nvim tty, instead we open a pipe, read output and display to the user. This is the only way the bang commands will be consistent across UIs, so programs designed to be used interactively from the terminal will no longer work from inside nvim.
If you’re interested in learning more about this, these two issues have some good information.
- :! (bang) and system() are not interactive / show ANSI codes
- Use :terminal for opening shell commands found in &keywordprg
The following works for me in Neovim
git log --graph --pretty=format:'%h - %d %s (%cr) <%an>' | nvim -R -c 'set hidden nowrap keywordprg=:enew\ \|\ terminal\ \git\ --no-pager\ show | nnoremap q :bd!<cr>' -
The Git portion of the mapping is the same but the Vim/Neovim part works differently.
hiddenallows switching away from an unsaved buffer
nowrapturns off line wrapping (so single line commits
:enewopens a new buffer and switches to it (away from our unsaved buffer)
terminalstarts a terminal session
git --no-pager showruns git show in the terminal without paging
nnoremap q :bd!<cr>remaps
qto quit the buffer
My next step is to setup this command as a Bash alias, so it is easier to run.