1
0
mirror of https://github.com/git/git.git synced 2024-10-04 07:32:33 +02:00
git/contrib/completion/git-completion.bash
Shawn O. Pearce 873537fadc Take --git-dir into consideration during bash completion.
If the user has setup a command line of "git --git-dir=baz" then
anything we complete must be performed within the scope of "baz"
and not the current working directory.

This is useful with commands such as "git --git-dir=git.git log m"
to complete out "master" and view the log for the master branch of
the git.git repository.  As a nice side effect this also works for
aliases within the target repository, just as git would honor them.

Unfortunately because we still examine arguments by absolute position
in most of the more complex commands (e.g. git push) using --git-dir
with those commands will probably still cause completion to fail.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-11-05 13:36:33 -08:00

399 lines
9.1 KiB
Bash
Executable File

#
# bash completion support for core Git.
#
# Copyright (C) 2006 Shawn Pearce
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
#
# The contained completion routines provide support for completing:
#
# *) local and remote branch names
# *) local and remote tag names
# *) .git/remotes file names
# *) git 'subcommands'
# *) tree paths within 'ref:path/to/file' expressions
#
# To use these routines:
#
# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
# 2) Added the following line to your .bashrc:
# source ~/.git-completion.sh
#
__gitdir ()
{
echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
}
__git_refs ()
{
local cmd i is_hash=y dir="${1:-$(__gitdir)}"
if [ -d "$dir" ]; then
cmd=git-peek-remote
else
cmd=git-ls-remote
fi
for i in $($cmd "$dir" 2>/dev/null); do
case "$is_hash,$i" in
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
n,*) is_hash=y; echo "$i" ;;
esac
done
}
__git_refs2 ()
{
local cmd i is_hash=y dir="${1:-$(__gitdir)}"
if [ -d "$dir" ]; then
cmd=git-peek-remote
else
cmd=git-ls-remote
fi
for i in $($cmd "$dir" 2>/dev/null); do
case "$is_hash,$i" in
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
n,*) is_hash=y; echo "$i:$i" ;;
esac
done
}
__git_remotes ()
{
local i ngoff IFS=$'\n' d="$(__gitdir)"
shopt -q nullglob || ngoff=1
shopt -s nullglob
for i in "$d/remotes"/*; do
echo ${i#$d/remotes/}
done
[ "$ngoff" ] && shopt -u nullglob
for i in $(git --git-dir="$d" repo-config --list); do
case "$i" in
remote.*.url=*)
i="${i#remote.}"
echo "${i/.url=*/}"
;;
esac
done
}
__git_complete_file ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
?*:*)
local pfx ls ref="$(echo "$cur" | sed 's,:.*$,,')"
cur="$(echo "$cur" | sed 's,^.*:,,')"
case "$cur" in
?*/*)
pfx="$(echo "$cur" | sed 's,/[^/]*$,,')"
cur="$(echo "$cur" | sed 's,^.*/,,')"
ls="$ref:$pfx"
pfx="$pfx/"
;;
*)
ls="$ref"
;;
esac
COMPREPLY=($(compgen -P "$pfx" \
-W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
| sed '/^100... blob /s,^.* ,,
/^040000 tree /{
s,^.* ,,
s,$,/,
}
s/^.* //')" \
-- "$cur"))
;;
*)
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
esac
}
__git_aliases ()
{
local i IFS=$'\n'
for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
case "$i" in
alias.*)
i="${i#alias.}"
echo "${i/=*/}"
;;
esac
done
}
__git_aliased_command ()
{
local word cmdline=$(git --git-dir="$(__gitdir)" \
repo-config --get "alias.$1")
for word in $cmdline; do
if [ "${word##-*}" ]; then
echo $word
return
fi
done
}
_git_branch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
}
_git_cat_file ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${COMP_WORDS[0]},$COMP_CWORD" in
git-cat-file*,1)
COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
;;
git,2)
COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
;;
*)
__git_complete_file
;;
esac
}
_git_checkout ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
}
_git_diff ()
{
__git_complete_file
}
_git_diff_tree ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
}
_git_fetch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${COMP_WORDS[0]},$COMP_CWORD" in
git-fetch*,1)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
git,2)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
*)
case "$cur" in
*:*)
cur=$(echo "$cur" | sed 's/^.*://')
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
*)
local remote
case "${COMP_WORDS[0]}" in
git-fetch) remote="${COMP_WORDS[1]}" ;;
git) remote="${COMP_WORDS[2]}" ;;
esac
COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
;;
esac
;;
esac
}
_git_ls_remote ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
}
_git_ls_tree ()
{
__git_complete_file
}
_git_log ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
*..*)
local pfx=$(echo "$cur" | sed 's/\.\..*$/../')
cur=$(echo "$cur" | sed 's/^.*\.\.//')
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
;;
*)
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
esac
}
_git_merge_base ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
}
_git_pull ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${COMP_WORDS[0]},$COMP_CWORD" in
git-pull*,1)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
git,2)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
*)
local remote
case "${COMP_WORDS[0]}" in
git-pull) remote="${COMP_WORDS[1]}" ;;
git) remote="${COMP_WORDS[2]}" ;;
esac
COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
;;
esac
}
_git_push ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${COMP_WORDS[0]},$COMP_CWORD" in
git-push*,1)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
git,2)
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
;;
*)
case "$cur" in
*:*)
local remote
case "${COMP_WORDS[0]}" in
git-push) remote="${COMP_WORDS[1]}" ;;
git) remote="${COMP_WORDS[2]}" ;;
esac
cur=$(echo "$cur" | sed 's/^.*://')
COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
;;
*)
COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
;;
esac
;;
esac
}
_git_reset ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
local opt="--mixed --hard --soft"
COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
}
_git_show ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
}
_git ()
{
local i c=1 command __git_dir
while [ $c -lt $COMP_CWORD ]; do
i="${COMP_WORDS[c]}"
case "$i" in
--git-dir=*) __git_dir="${i#--git-dir=}" ;;
--bare) __git_dir="." ;;
--version|--help|-p|--paginate) ;;
*) command="$i"; break ;;
esac
c=$((++c))
done
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
COMPREPLY=($(compgen \
-W "--git-dir= --version \
$(git help -a|egrep '^ ') \
$(__git_aliases)" \
-- "${COMP_WORDS[COMP_CWORD]}"))
return;
fi
local expansion=$(__git_aliased_command "$command")
[ "$expansion" ] && command="$expansion"
case "$command" in
branch) _git_branch ;;
cat-file) _git_cat_file ;;
checkout) _git_checkout ;;
diff) _git_diff ;;
diff-tree) _git_diff_tree ;;
fetch) _git_fetch ;;
log) _git_log ;;
ls-remote) _git_ls_remote ;;
ls-tree) _git_ls_tree ;;
merge-base) _git_merge_base ;;
pull) _git_pull ;;
push) _git_push ;;
reset) _git_reset ;;
show) _git_show ;;
show-branch) _git_log ;;
whatchanged) _git_log ;;
*) COMPREPLY=() ;;
esac
}
_gitk ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
}
complete -o default -o nospace -F _git git
complete -o default -F _gitk gitk
complete -o default -F _git_branch git-branch
complete -o default -o nospace -F _git_cat_file git-cat-file
complete -o default -F _git_checkout git-checkout
complete -o default -o nospace -F _git_diff git-diff
complete -o default -F _git_diff_tree git-diff-tree
complete -o default -o nospace -F _git_fetch git-fetch
complete -o default -o nospace -F _git_log git-log
complete -o default -F _git_ls_remote git-ls-remote
complete -o default -o nospace -F _git_ls_tree git-ls-tree
complete -o default -F _git_merge_base git-merge-base
complete -o default -o nospace -F _git_pull git-pull
complete -o default -o nospace -F _git_push git-push
complete -o default -F _git_reset git-reset
complete -o default -F _git_show git-show
complete -o default -o nospace -F _git_log git-show-branch
complete -o default -o nospace -F _git_log git-whatchanged
# The following are necessary only for Cygwin, and only are needed
# when the user has tab-completed the executable name and consequently
# included the '.exe' suffix.
#
if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
complete -o default -o nospace -F _git git.exe
complete -o default -F _git_branch git-branch.exe
complete -o default -o nospace -F _git_cat_file git-cat-file.exe
complete -o default -o nospace -F _git_diff git-diff.exe
complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
complete -o default -o nospace -F _git_log git-log.exe
complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
complete -o default -F _git_merge_base git-merge-base.exe
complete -o default -o nospace -F _git_push git-push.exe
complete -o default -o nospace -F _git_log git-show-branch.exe
complete -o default -o nospace -F _git_log git-whatchanged.exe
fi