hack

Git: autocomplete –trailer and –cc in zsh

Firmin Martin
· 閱讀時間:2 分鐘
zshgitfzfautocomplete

Introduction

When working on a Git repository developped through email-based workflow (e.g. Git, Linux kernel, Emacs, notmuch etc.), it is often needed

  • to git commit with the --trailer option to acknowledge people,
  • and to git send-email with the --to & -cc options to indicate the recipients of the patch series to send.

Newcomers of such workflow, as me, would copy one by one the email addresses from git-log or the project mailing list at the beginning. But it becomes quickly tiresome. The good news is that this process can be automatized with fzf and zsh (see the Screencasts section).

Let’s make a fake Git repository to illustrate how it works. The following snippet will create at most 1500 empty commits from 150 distinct developers. It uses rig1 On Ubuntu, sudo apt install rig. to create fake identities.

1
DIR=~/tmp/Git_fzf/ mkdir -p $DIR && cd $DIR
2
git init
3
rig -c 150 | awk -v RS='\n\n' '{print $1 " " $2}' |
4
while read name; do
5
for i in {1..$(( RANDOM % 10 + 1 ))}; do
6
git commit --author "$name <${${name// /.}:l}@domain.com>" --allow-empty --allow-empty-message -m "";
7
done
8
done
    image

    Figure 1: Creating a fake Git repository with distinct authors.

    Fetching email addresses of developers

    The following command returns all email addresses of the current Git repository’s developers.

    1
    git shortlog -sne --all | cut -f2

      Breaking it down, we instruct git shortlog

      • to suppress commit descriptions (-s),
      • to sort the contributors by the number of commits (-n),
      • to provide contributors’ email (-e),
      • and to consider the developers of all branches (--all).

      Piping the result to cut -f2 helps us to get rid of the commits count.

      Select email addresses

      Now, we want to pick out some addresses we are interested in. This step requires that the fuzzy filter fzf is installed.

      It’s pretty simple: we just have to pipe the result of git-shortlog to fzf and use the option -m to enable multiple choices. The --reverse option makes a drop-down menu which I find less disruptive.

      1
      git shortlog -sne --all | cut -f2 | fzf -m --reverse

        Now you can select/unselect emails with TAB / Shift+TAB. Once you are done, press RET. It will output the selected entries.

        Select git-commit trailers and git-send-email recipients options

        We can also make a drop-down menu to select git-commit trailers and recipients options. Let’s wrap it in a function.

        1
        __fzf_git_trailer_and_option() {
        2
        cat <<- EOF | fzf --reverse
        3
        --to=
        4
        --bcc=
        5
        --cc=
        6
        --trailer Thanks-to:
        7
        --trailer Reviewed-by:
        8
        --trailer Reported-by:
        9
        --trailer Acked-by:
        10
        --trailer Tested-by:
        11
        --trailer Based-on-patch-by:
        12
        --trailer Mentored-by:
        13
        EOF
        14
        }

          Detect if we are under a Git repository

          The command git rev-parse --is-inside-work-tree can tell whether we are under a Git repository. Let’s enable autocompletion only in such situation. We wrap this into a function which, given a selected trailer or option and potentially multiple addresses, returns addresses prefixed by the selected trailer or option.

          1
          __fzf_git_authors() {
          2
          if $(git rev-parse --is-inside-work-tree 2>/dev/null); then
          3
          local trailer_or_option=$(__fzf_git_trailer_and_option)
          4
          git shortlog -sne --all | cut -f2 | fzf -m --reverse |
          5
          while read item; do
          6
          echo -n "${trailer_or_option}'${item}' "
          7
          done
          8
          fi
          9
          }

            Bind autocompletion to a shortcut

            So far, the result is outputted to the terminal, but we actually want that it appends the current command line. So, we keep the content on the left of the buffer and redisplay it.

            1
            fzf-git-authors() {
            2
            LBUFFER="${LBUFFER}$(__fzf_git_authors)"
            3
            zle redisplay
            4
            typeset -f zle-line-init >/dev/null && zle zle-line-init
            5
            }

              Finally, I bound that function to Alt-E`.

              1
              zle -N fzf-git-authors
              2
              bindkey '\ee' fzf-git-authors

                Screencasts

                image

                Figure 2: git-commit with --trailer autocompletion.

                image

                Figure 3: git-send-email with recipients autocompletion.

                Footnotes

                1. On Ubuntu, sudo apt install rig.