Git lg with links

This post first appeared 7 January 2023.

Click on commit hashes in git log --graph in order to check out that commit.

I’ve recently started using the terminal kitty, and something that’s impressed me is the custom handling of terminal hyperlinks.

While clicking on files to open them in your chosen editor, or cd to the directory output of ls --hyperlink=auto is neat, something I’ve been doing a lot of recently is jumping between commits in a complicated git history. Wouldn’t it be neat if I could do that without having to remember commit hashes?

The version of git log I use comes from this Coderwall post with a few slight modifications:

[alias]
  lg = "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --abbrev-commit --all

You can see a picture below.

To make things clickable, we need to send some more control codes, similar to the ANSII escape codes that give the text its colour. The “OSC 8” hyperlink standard is detailed here1, but we will need to specify an URI for our commit. Unfortunately it seems that there isn’t a good agreement on git:// URI’s so I’m rolling my own:

git://path/to/repo#<COMMIT_SHA>

Since we will assume we are always within the repo when we run git lg, here’s the config I came up with:

[alias]
  lg = "log --color --graph --pretty=format:'^[]8;;git://.#%h^[\\%Cred%h%Creset^[]8;;^[\\ -%C(yellow)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --abbrev-commit --all"

Just to be clear, the characters ^[ are a literal ESC sequence — the character 0x1b2. Doing something like cat ~/.gitconfig doesn’t show them as they are piped to the terminal: you have to use the -v switch.

Here’s a picture of the result. Note that the terminal is highlighting (underlining) the linked hypertext under the cursor.

On the terminal side, kitty has built in support for customising URI handling. To tell it about our new scheme, we simply need to add the following lines to ~/.config/kitty/open-actions.conf.

# Open git commit hashes of the form
#   git://.#<COMMIT_SHA>
# by checking them out.
protocol git
action launch --cwd=current sh -c "git checkout $FRAGMENT"

Now we can run git lg, click on the link and we have checked out that commit.

Done.

Iterations

This is a very simple solution to the problem and has a host of limitations. However, I find it works fine for now. If you have any ideas for how to improve on it, drop me an email. I’d like to keep this simple (two config files and no executables). Once it starts doing anything too complex, I think it might be better to just switch to a terminal frontend like gitui.


  1. Just read the document. The comments get depressing. ↩︎

  2. You can enter this in (neo)vi(m) using Ctrl-v u 1 b Enter ↩︎