git: bringing CLI usability to parity with GitKraken

My first serious usage of git was with GitKraken - probably the gold standard of Git GUIs - but I’ve entirely replaced it with the CLI git tool now. It took a bit of work to reach parity with GitKraken in terms of usability. Some thoughts on my current git CLI workflow follow.

I will refer to the VCS as git, and the CLI tool as git.

Merges

My primary use case for opening GitKraken over the CLI was merges. However, the default behaviour of vimdiff, which git mergetool uses by default, is to give you a very difficult-to-parse 3-way diff (which is particularly painful on a small screen). To make it more usable, there is a lot to gain in:

  • The diffconflicts script. This is now available as a vim plugin. This gives you a two-pane diff - the left is your local, the right is your remote, and all you have to do is make the lefthand side correct. The right side is even read only, so it’s pretty hard to mess this up. Hook this into your workflow by setting your .gitconfig as described in the script README.

  • The vimdiff keybindings. A short cheatsheet that will get you through the vast majority of it:

    • ]c, [c: next and previous diff. If using diffconflicts, this means next and previous conflicting hunk.
    • do (“diff obtain”): grab lines from the specified buffer and write to current buffer. Note you can use linewise motions. If using diffconflicts, use this from the lefthand side to say “grab the hunk from the righthand side”. You can use standard vim yanks to go the other way.
    • cq: exit with error. If you can’t solve the diff, this is how you abort git mergetool without it thinking the conflicts are resolved.

Other built-in and (user|plugin)-defined vim shortcuts will work, of course. It is worth calling out that folds are defined for various hunks.

  • Modifying your colourschemes. To make things worse still, vimdiff chooses blue, pink and grey as its highlight colour for insertions, deletions, and modifications. I have the following in my .vimrc to set my (insert, delete, modify) highlighting colours to (green, red, purple). Perhaps I’m just ruined by learning on a GUI, though…
hi DiffAdd   ctermbg=NONE ctermfg=46  cterm=NONE guibg=NONE guifg=#00FF00 gui=NONE
hi DiffDelete ctermbg=NONE ctermfg=196 cterm=NONE guibg=NONE guifg=#FF0000 gui=NONE
hi DiffText ctermbg=NONE ctermfg=93 cterm=NONE guibg=NONE guifg=#FF00FF gui=NONE

It isn’t much, but the outcome is something like this:

vimdiff screenshot

Tracking repo history

The default main window of GitKraken has a tree of the repo state. This is something git can actually do, it’s just a major pain to type out. The following works pretty well:

  • At the bare minimum, alias something like git tree in your .gitconfig. Something like the following will give a bare-bones version, that can make it significantly easier to work out what’s going on by visualising the commit graph.
[alias]
    lg = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
  • To make it look a bit nicer, I have the following script saved as git-xtree in my path (modified from a post found once upon a time on stackoverflow). Apologies to the anti-zsh crowd for using it just for colors here.
#!/usr/bin/env zsh
autoload -U colors && colors

function test-cmd-exists() {
    if ! type $1 > /dev/null; then
        echo "$fg_bold[red]ERROR$reset_color: $1 not installed. aborting."
        exit 1
    fi
}
test-cmd-exists gawk

git log \
    --all \
    --graph \
    --decorate=short \
    --date-order \
    --color \
    --pretty=format:"%C(bold blue)%h%C(reset)§%C(dim normal)(%cr)%C(reset)§%C(auto)%d%C(reset)§§%n§§§       %C(normal)%an%C(reset)%C(dim normal): %s%C(reset)" \
    | gawk '{ \
        split($0,arr,"§"); \
        match(arr[2], /(\([0-9a-z ,]+\))/, rawtime); \
        padlen=24+length(arr[2])-length(rawtime[1]); \
        printf("%*s    %s %s %s\n", padlen, arr[2], arr[1], arr[3], arr[4]); \
    }' \
    | less -RFX -p $(git show -s --format=%h)

(also on Github here). The result (shout-out to taffybar which I arbitrarily cloned for this): GitKraken-style commit graphing

Diffs

I personally struggle to quickly parse diffs with the default formatting. Far, far nicer is delta, packaged as git-delta (at least on AUR and brew). The GitHub page is here. The screenshots will make a convincing case for it.

Auto-fetch

Not something I personally use, but if you’re after parity with GitKraken, you may want its autofetching feature. If you’re using zsh and oh-my-zsh, this is very easily doable with the built-in plugin git-auto-fetch - just add this to the end of your plugins list in your .zshrc. This will simply fire off a git fetch after each time you run a command in your terminal.

General edits while comitting

In short, if wanting to remain in-place while fixing typos, the solution is a terminal text editor you are comfortable with, and a way to rapidly get around the repo. Advice for the former is out of scope for this discussion. For the latter, I will just note that combining fzf (switch on the <C-t> support) and fd (and/or rg) makes it incredibly quick to jump into editing a file you’ve spotted a typo in.

It is also worth making use of -p. This flag is available on a lot of git commands, and runs the command on hunks, or patches, of code. For example, if you run git add -p file, it will run through each hunk of changes. For multi-line hunks, you can split further by hitting s at the prompt.