简体   繁体   中英

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

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 .

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".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM