Inverted git log --graph

Using git log --graph is nice, but I dislike that the most relevant commits, are shown at the top of the terminal screen. If your terminal scrolls some lines after quitting the graph pager, those commits will not be visible and you will need to scroll up.

Unfortunately --graph and --reverse cannot be used together.

You can use tac to invert the output, however the graph needs some adjustments to be properly drawn.

The script below substitutes:

FromTo
\/
/\
_̅

That will make the graph be properly shown in its reversed form.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import re
import sys

# Define substitution mappings and placeholder
FORWARD_SLASH = "/"
BACKSLASH = "\\"
PLACEHOLDER = "<<<SWAP_PLACEHOLDER>>>"

# Partition can be short hash or >=5 whitespaces
partition_re = re.compile(r"([0-9a-f]{7,12})|(\s{5,})")


def substitute_before_partition(line):
    match = partition_re.search(line)
    if match:
        idx = match.start()
        before = line[:idx]
        after = line[idx:]
    else:
        before = line
        after = ""
    before = before.replace(FORWARD_SLASH, PLACEHOLDER)
    before = before.replace(BACKSLASH, FORWARD_SLASH)
    before = before.replace(PLACEHOLDER, BACKSLASH)
    before = before.replace("_", " \u0305")

    return before + after


if __name__ == "__main__":
    for line in sys.stdin:
        print(substitute_before_partition(line.rstrip("\n")))

Then we can combine the script with tac and less, to have essentially the same behavior as the original git log --graph, but inverted:

1
git log --graph 2>&1 | tac | python git_log_graph_invert_characters.py | less -FX +G

Bonus Tip: ZSH Completions on alias

If you use just an alias, in your config you’ll lose the completions provided by zsh. If you set up the alias as a function, you can retain completions. For example, when you want to look at a few branches, the git completions will show the available branches, and if you use fzf, you can easily select one.

For zsh to provide completions on the new commands you need to use a function and compdef. In your .zshrc, place the function definitions and after them, use compdef:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
invert_gitgraph() {
  local cmd="$1"; shift
  "$cmd" "$@" 2>&1 | tac | python <path to git_log_graph_invert_characters.py> | less -FX +G
  # WARN: make sure to set the path to git_log_graph_invert_characters.py according to your system
}

gitgraph() {
  git log --graph --oneline --color "$@"
}

gl() { invert_gitgraph gitgraph "$@"; }

compdef _git gl=git-log

For extra reference you can check my nixos-config.

Here’s an example of what it looks like: