• Skip to primary navigation
  • Skip to main content
Sal Ferrarello
  • About Sal Ferrarello
  • Speaking
  • Connect
    Mastodon GitHub Twitter (inactive)
You are here: Home / Computing / Using Vim to View Git Commits
The Git and Vim Logos Together

Using Vim to View Git Commits

Last updated on February 23, 2018 by Sal Ferrarello

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 man.

Vim automatically sets keywordprg for some filetypes, including the filetype git. When the filetype is set to git, keywordprg is set to git show.

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 git log.

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' -

Explanation

Git Output

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.

  • –graph
  • –pretty=format
    • %h – abbreviated commit hash
    • %d – ref names, like the –decorate option of git-log
    • %s – subject
    • %cr – committer date, relative
    • %an – author name

Vim Settings

When I feed my customized git log output into Vim, Vim fails to set the filetype to git.

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.

  • set hidden allows switching away from an unsaved buffer
  • set nowrap turns off line wrapping (so single line commits
  • set keywordprg
    • :enew opens a new buffer and switches to it (away from our unsaved buffer)
    • terminal starts a terminal session
    • git --no-pager show runs git show in the terminal without paging
    • nnoremap q :bd!<cr> remaps q to quit the buffer

Next Steps

My next step is to setup this command as a Bash alias, so it is easier to run.

Sal Ferrarello
Sal Ferrarello (@salcode)
Sal is a PHP developer with a focus on the WordPress platform. He is a conference speaker with a background including Piano Player, Radio DJ, Magician/Juggler, Beach Photographer, and High School Math Teacher. Sal can be found professionally at WebDevStudios, where he works as a senior backend engineer.

Share this post:

Share on TwitterShare on FacebookShare on LinkedInShare on EmailShare on Reddit

Filed Under: Computing, Dev Tips Tagged With: command line, Git, vim

Reader Interactions

Comments

  1. Rich Cheng says

    February 21, 2018 at 12:03 pm

    > I’m guessing Vim recognizes the standard format of git log

    Yup. See:

    :e $VIMRUNTIME/scripts.vim | /Git
    Reply
    • Sal Ferrarello says

      February 21, 2018 at 12:45 pm

      Hi Rich,

      Thanks for confirming and especially thanks for the command to see the relevant code – that is awesome.

      If anyone else want to see the relevant code, running Rich’s line in Vim will take you to the correct spot in the correct file. You can also see the code on GitHub.

      Reply
  2. Jason Carpenter says

    February 21, 2018 at 3:51 pm

    alias glog="vim -R -c 'set filetype=git nowrap' <(git log --graph --pretty=format:'%h - %d %s (%cr) ')"
    
    Reply
  3. Anders Sildnes says

    February 22, 2018 at 9:58 am

    In ~/.gitconfig (or wherever else you store git config)

    [core]
      editor = vim
      pager = "vim -R"
    

    the pager variable can receive bash expressions, e.g:
    pager = if [ $X = "this"] then vim -R ; else less

    Reply
    • Anders Sildnes says

      February 22, 2018 at 10:08 am

      … Which is easier than creating aliases 🙂

      Reply
    • Ryan Lue says

      March 1, 2018 at 2:07 am

      Moreover, the AnsiEsc.vim plugin enables ANSI escape coloring in vim:

      https://github.com/vim-scripts/AnsiEsc.vim

      so Sal’s original improved-version-of-git-log can actually be made to work, with two caveats:

      1. the `:AnsiEsc` command must be executed first; and
      2. when pressing ‘K’ over a commit hash, vim thinks that the ANSI escape codes are part of the commit hash itself.

      The following works:

      git log –color –graph –pretty=format:’%Cred %h %Creset-%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)%Creset’ | vim -R -c ‘set filetype=git nowrap’ -c ‘AnsiEsc’ –

      Combining your git config lines with his:

      # ~/.config/git/config
      [core]
      pager = “vim -R -c ‘set filetype=git nowrap’ -c ‘AnsiEsc’ -”
      [alias]
      lg = log –color –graph –pretty=format:’%Cred %h %Creset-%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)%Creset’

      Reply
  4. xeR0 says

    February 22, 2018 at 10:42 am

    this is very cool! and makes me think of a few ideas with keywordprg, but for git history viewing i still think the gv plugin is better (colors, diffs open in splits, more options, more interactive, etc) https://github.com/junegunn/gv.vim

    Reply
  5. Sourabh Jain says

    August 16, 2019 at 1:26 am

    I don’t think it is a good idea to pipe the git log output to vim (git log | vim -R -)

    If the project has a huge log history then it takes forever to complete the operation.

    Reply
    • Sal Ferrarello says

      August 16, 2019 at 10:05 am

      You’re right, keeping the possibility of a very large number of commits in mind is a good idea. My first thought would be to limit the results to the first n commits, e.g. --max-count=1000. Thanks for bringing this up.

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Copyright © 2023 · Bootstrap4 Genesis on Genesis Framework · WordPress · Log in