Reputation: 18888
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:
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.
Upvotes: 4
Views: 837
Reputation: 52506
Let's assume a minimal version of your script, something like
#!/usr/bin/env bash
git diff "$@"
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 ; ... '".
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".
Upvotes: 5