Key bindings for git with fzf
2016. 07. 17.

The latest version of fzf has --preview option which allows you to preview the content of the highlighted entry on a split window inside fzf finder.

--preview

This was a huge step for fzf. The feature was requested several times in the past, but I was always concerned that it would hurt the simplicity of fzf and dismissed the idea, but in the end I conceded, and now I have to say that I like it pretty much.

One of the places I find --preview option extremely useful is the bash key bindings I have for git commands. With its numerous subcommands and options, git can be quite daunting even for the experienced. There is sophisticated, context-aware completion support for git command, but I find it lacking in a few aspects.

Alternatively, I wrote explicit key bindings for each type of git object; commit hashes, branches, tags, remotes, and the files that are modified or untracked.

They are implemented on fzf, so we have nice interactive finder that enables fast fuzzy search over the list. And with the new --preview option of fzf, we not only see the list of the objects, but also the details of each entry.

The simplest example is CTRL-GCTRL-T.

# Will return non-zero status if the current directory is not managed by git
is_in_git_repo() {
  git rev-parse HEAD > /dev/null 2>&1
}

gt() {
  # "Nothing to see here, move along"
  is_in_git_repo || return

  # Pass the list of the tags to fzf-tmux
  # - "{}" in preview option is the placeholder for the highlighted entry
  # - Preview window can display ANSI colors, so we enable --color=always
  # - We can terminate `git show` once we have $LINES lines
  git tag --sort -version:refname |
    fzf-tmux --multi --preview-window right:70% \
             --preview 'git show --color=always {} | head -'$LINES
}

Then we bind it to a key.

bind '"\er": redraw-current-line'
bind '"\C-g\C-t": "$(gt)\e\C-e\er"'

A couple things to note:

On zsh, gt function works without any change, but we should use bindkey instead of bind and define a widget for each key binding.

# A helper function to join multi-line output from fzf
join-lines() {
  local item
  while read item; do
    echo -n "${(q)item} "
  done
}

fzf-gt-widget() LBUFFER+=$(gt | join-lines)
zle -N fzf-gt-widget
bindkey '^g^t' fzf-gt-widget

Now if you press CTRL-GCTRL-T on a git repository you can select multiple tags in fzf and they will be pasted on the command-line prompt as shown below.


You can find the code for the rest here. My current favorites are CTRL-GCTRL-F and CTRL-GCTRL-H.

» capture | close