How can I make tab completion for my Git alias behave like an existing command?

Greg Burghardt

I am writing a shell script to add a "review" sub command to git, to make it easier to do code reviews. It's basically a fancy wrapper for git diff and git difftool commands, but requires less typing.

Some example usages:

# Lists added, deleted, renamed and modified files between master and current branch
git review master -l

# Opens difftool for files modified between master and current branch
git review -m

I would like to enable branch auto completion in my shell script, but cannot for the life of me figure out how to do it. Here is what I'm really after:

git review ma<tab><tab>

And then it should behave like git checkout ma<tab><tab>.

My shell script:

#!/bin/env bash

function print_usage {
    echo "Usage: git review <branch> <-a|-d|-m|-l> [-- paths/to filter/by]"
    echo ""
    echo "    -a: Only review added files"
    echo "    -d: Only review delete files"
    echo "    -m: Only review modified files"
    echo "    -l: List files and and type of modification"
}

if [ -z "$1" ] || [ -z "$2" ]; then
    print_usage
    exit 1
fi

git_branch=$1
review_command=$2
path_filters=""

shift
shift

if [ "$1" = "--" ]; then
    path_filters="$@"
fi

case $review_command in
    "-a")
        echo "Reviewing added files..."

        if [ -z "$path_filters" ]; then
            git difftool $git_branch -- $(git diff --name-status $git_branch | grep -E '^A' | awk '{print $2}')
        else
            git difftool $git_branch -- $(git diff --name-status $git_branch -- $path_filters | grep -E '^A' | awk '{print $2}')
        fi
        ;;
    "-d")
        echo "Reviewing deleted files..."

        if [ -z "$path_filters" ]; then
            git difftool $git_branch -- $(git diff --name-status $git_branch | grep -E '^D' | awk '{print $2}')
        else
            git difftool $git_branch -- $(git diff --name-status $git_branch -- $path_filters | grep -E '^D' | awk '{print $2}')
        fi
        ;;
    "-m")
        echo "Reviewing modified files..."

        if [ -z "$path_filters" ]; then
            git difftool $git_branch -- $(git diff --name-status $git_branch | grep -E '^M' | awk '{print $2}')
        else
            git difftool $git_branch -- $(git diff --name-status $git_branch -- $path_filters | grep -E '^M' | awk '{print $2}')
        fi
        ;;
    "-l")
        echo "Differences between $git_branch and $(git mybranch)..."

        if [ -z "$path_filters" ]; then
            git diff --name-status $git_branch
        else
            git diff --name-status $git_branch -- $path_filters
        fi
        ;;
esac

echo ""
echo "Review finished."

Really, since I'm in the process of typing the command in, I doubt my shell script will have anything to do with the solution.

Some other useful info:

  • Windows 10
  • Git v2.18.0.windows.1
  • Shell: GNU bash, version 4.4.19(2)-release (x86_64-pc-msys)

Is there a way to add git branch auto completion to a custom git extension command?


An interesting related question for Linux: custom git command autocompletion.

Benjamin W.

Using an alias

Let's assume a minimal version of your script, something like

#!/usr/bin/env bash

git diff "$1"

This is executable and somewhere in your $PATH. Let's call it gitreview.

To get an alias for it, you add it like this in your .gitconfig:

[alias]
    review =  "!f() { gitreview \"$@\"; }; f"

This gets you completion for review when you enter git. Now, to make it behave the same as git checkout, you can use a null command, like this:

review =  "!f() { : git checkout ; gitreview \"$@\"; }; f"

and it'll complete the same as git checkout! Notice that the blank between checkout and ; is required.


This is mentioned in the comments of git-completion.bash:

# If you use complex aliases of form '!f() { ... }; f', you can use the null
# command ':' as the first command in the function body to declare the desired
# completion style.  For example '!f() { : git commit ; ... }; f' will
# tell the completion to use commit completion.  This also works with aliases
# of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".

Using an external command

Alternatively, you can make your script a proper external command by naming it git-review and leave it somewhere in your $PATH. To get completion for it (assuming you have both Bash and Git completion), add this to your ~/.bash_completion file (just create it if it doesn't exist):

_git_review() { _git_checkout; }

Git completion (for Git 2.18 or newer) checks for completion functions that are named _git_$command, and by doing this, you say "just call _git_checkout instead".

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How do I make Vim do normal (Bash-like) tab completion for file names?

How can I make an arbitrary UIAccessibilityElement behave like a UISwitch for VoiceOver?

How can I make my vim behave like my cat?

How can I make my app behave like I'm changing Application is agent(UIElement) at runtime using Swift?

How to make bash completion work for git alias?

How can I expand a relative path at the command line, with tab completion?

How can I make zsh completion behave like Bash completion?

How can I get bash to perform tab-completion for my aliases?

How can I make my shell behave like vim?

Can I make my Synology NAS behave more like a normal external hard drive?

How can I make my Super keys (Windows Key) behave more like Ctrl/Alt/Shift in Linux

How do I make iOS 7 Control Center behave like it does in Maps (small tab)?

How can I make an H4 element behave like an HR when floats are present

How do you make an alias or function that retains tab completion?

ZSH tab completion of git commands is very slow. How can I turn it off?

How can I make firefox behave like IE on a windows domain when requesting user credentials

How can I make a column of check boxes in the ObjectListView behave like radio buttons?

zsh completion: make sshrc behave like ssh

How can I extend the Tab key auto-completion in the terminal to text in the middle of a command?

How do I make bash completion behave like this?

How do I make bash do vim-like tab completion for file names?

How can I make a volatile struct behave exactly like a volatile int during assignment?

How can I make this git alias with quotes work?

How can I add this lengthy command as alias on git?

How can I make an alias for a long ls command?

How can I make Underscore behave like Ramda?

How can I make SublimeText version 4's autocomplete behave like version 3?

Can I make the clear command behave like Ctrl-L in Bash?

How can I output "temporarily" to the shell, like zsh tab completion does?