1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-10-31 22:37:54 +01:00
git/contrib/completion/git-completion.bash

2277 lines
44 KiB
Bash
Raw Normal View History

#!bash
#
# bash completion support for core Git.
#
# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
# Distributed under the GNU General Public License, version 2.0.
#
# 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
# *) common --long-options
#
# 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
#
# 3) Consider changing your PS1 to also show the current branch:
# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#
# The argument to __git_ps1 will be displayed only if you
# are currently in a git repository. The %s token will be
# the name of the current branch.
#
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
# value, unstaged (*) and staged (+) changes will be shown next
# to the branch name. You can configure this per-repository
# with the bash.showDirtyState variable, which defaults to true
# once GIT_PS1_SHOWDIRTYSTATE is enabled.
#
# You can also see if currently something is stashed, by setting
# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
# then a '$' will be shown next to the branch name.
#
# If you would like to see if there're untracked files, then you can
# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
# untracked files, then a '%' will be shown next to the branch name.
#
# To submit patches:
#
# *) Read Documentation/SubmittingPatches
# *) Send all patches to the current maintainer:
#
# "Shawn O. Pearce" <spearce@spearce.org>
#
# *) Always CC the Git mailing list:
#
# git@vger.kernel.org
#
case "$COMP_WORDBREAKS" in
*:*) : great ;;
*) COMP_WORDBREAKS="$COMP_WORDBREAKS:"
esac
# __gitdir accepts 0 or 1 arguments (i.e., location)
# returns location of .git repo
__gitdir ()
{
if [ -z "${1-}" ]; then
if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
elif [ -d .git ]; then
echo .git
else
git rev-parse --git-dir 2>/dev/null
fi
elif [ -d "$1/.git" ]; then
echo "$1/.git"
else
echo "$1"
fi
}
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# returns text to add to bash PS1 prompt (includes branch name)
__git_ps1 ()
{
local g="$(__gitdir)"
if [ -n "$g" ]; then
local r
local b
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
else
if [ -d "$g/rebase-apply" ]; then
if [ -f "$g/rebase-apply/rebasing" ]; then
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
else
r="|AM/REBASE"
fi
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
b="$(git symbolic-ref HEAD 2>/dev/null)" || {
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
(contains)
git describe --contains HEAD ;;
(branch)
git describe --contains --all HEAD ;;
(describe)
git describe HEAD ;;
(* | default)
git describe --exact-match HEAD ;;
esac 2>/dev/null)" ||
b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
b="unknown"
b="($b)"
}
fi
local w
local i
local s
local u
local c
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
else
b="GIT_DIR!"
fi
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
git diff --no-ext-diff --quiet --exit-code || w="*"
if git rev-parse --quiet --verify HEAD >/dev/null; then
git diff-index --cached --quiet HEAD -- || i="+"
else
i="#"
fi
fi
fi
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
fi
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
u="%"
fi
fi
fi
local f="$w$i$s$u"
printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r"
fi
}
# __gitcomp_1 requires 2 arguments
__gitcomp_1 ()
{
local c IFS=' '$'\t'$'\n'
for c in $1; do
case "$c$2" in
--*=*) printf %s$'\n' "$c$2" ;;
*.) printf %s$'\n' "$c$2" ;;
*) printf %s$'\n' "$c$2 " ;;
esac
done
}
# __gitcomp accepts 1, 2, 3, or 4 arguments
# generates completion reply with compgen
__gitcomp ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
if [ $# -gt 2 ]; then
cur="$3"
fi
case "$cur" in
--*=)
COMPREPLY=()
;;
*)
local IFS=$'\n'
COMPREPLY=($(compgen -P "${2-}" \
-W "$(__gitcomp_1 "${1-}" "${4-}")" \
-- "$cur"))
;;
esac
}
# __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
__git_heads ()
{
local cmd i is_hash=y dir="$(__gitdir "${1-}")"
if [ -d "$dir" ]; then
git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
refs/heads
return
fi
for i in $(git ls-remote "${1-}" 2>/dev/null); do
case "$is_hash,$i" in
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
n,*) is_hash=y; echo "$i" ;;
esac
done
}
# __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
__git_tags ()
{
local cmd i is_hash=y dir="$(__gitdir "${1-}")"
if [ -d "$dir" ]; then
git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
refs/tags
return
fi
for i in $(git ls-remote "${1-}" 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,*) is_hash=y; echo "$i" ;;
esac
done
}
# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
__git_refs ()
{
local i is_hash=y dir="$(__gitdir "${1-}")"
local cur="${COMP_WORDS[COMP_CWORD]}" format refs
if [ -d "$dir" ]; then
case "$cur" in
refs|refs/*)
format="refname"
refs="${cur%/*}"
;;
*)
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
if [ -e "$dir/$i" ]; then echo $i; fi
done
format="refname:short"
refs="refs/tags refs/heads refs/remotes"
;;
esac
git --git-dir="$dir" for-each-ref --format="%($format)" \
$refs
return
fi
for i in $(git ls-remote "$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,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
n,*) is_hash=y; echo "$i" ;;
esac
done
}
# __git_refs2 requires 1 argument (to pass to __git_refs)
__git_refs2 ()
{
local i
for i in $(__git_refs "$1"); do
echo "$i:$i"
done
}
# __git_refs_remotes requires 1 argument (to pass to ls-remote)
__git_refs_remotes ()
{
local cmd i is_hash=y
for i in $(git ls-remote "$1" 2>/dev/null); do
case "$is_hash,$i" in
n,refs/heads/*)
is_hash=y
echo "$i:refs/remotes/$1/${i#refs/heads/}"
;;
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
n,refs/tags/*) is_hash=y;;
n,*) is_hash=y; ;;
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" config --get-regexp 'remote\..*\.url' 2>/dev/null); do
i="${i#remote.}"
echo "${i/.url*/}"
done
}
__git_list_merge_strategies ()
{
git merge -s help 2>&1 |
sed -n -e '/[Aa]vailable strategies are: /,/^$/{
s/\.$//
s/.*://
s/^[ ]*//
s/[ ]*$//
p
}'
}
__git_merge_strategies=
# 'git merge -s help' (and thus detection of the merge strategy
# list) fails, unfortunately, if run outside of any git working
# tree. __git_merge_strategies is set to the empty string in
# that case, and the detection will be repeated the next time it
# is needed.
__git_compute_merge_strategies ()
{
: ${__git_merge_strategies:=$(__git_list_merge_strategies)}
}
__git_complete_file ()
{
local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
?*:*)
ref="${cur%%:*}"
cur="${cur#*:}"
case "$cur" in
?*/*)
pfx="${cur%/*}"
cur="${cur##*/}"
ls="$ref:$pfx"
pfx="$pfx/"
;;
*)
ls="$ref"
;;
esac
case "$COMP_WORDBREAKS" in
*:*) : great ;;
*) pfx="$ref:$pfx" ;;
esac
local IFS=$'\n'
COMPREPLY=($(compgen -P "$pfx" \
-W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
| sed '/^100... blob /{
s,^.* ,,
s,$, ,
}
/^120000 blob /{
s,^.* ,,
s,$, ,
}
/^040000 tree /{
s,^.* ,,
s,$,/,
}
s/^.* //')" \
-- "$cur"))
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
__git_complete_revlist ()
{
local pfx cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
*...*)
pfx="${cur%...*}..."
cur="${cur#*...}"
__gitcomp "$(__git_refs)" "$pfx" "$cur"
;;
*..*)
pfx="${cur%..*}.."
cur="${cur#*..}"
__gitcomp "$(__git_refs)" "$pfx" "$cur"
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
__git_complete_remote_or_refspec ()
{
local cmd="${COMP_WORDS[1]}"
local cur="${COMP_WORDS[COMP_CWORD]}"
local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
while [ $c -lt $COMP_CWORD ]; do
i="${COMP_WORDS[c]}"
case "$i" in
--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
--all)
case "$cmd" in
push) no_complete_refspec=1 ;;
fetch)
COMPREPLY=()
return
;;
*) ;;
esac
;;
-*) ;;
*) remote="$i"; break ;;
esac
c=$((++c))
done
if [ -z "$remote" ]; then
__gitcomp "$(__git_remotes)"
return
fi
if [ $no_complete_refspec = 1 ]; then
COMPREPLY=()
return
fi
[ "$remote" = "." ] && remote=
case "$cur" in
*:*)
case "$COMP_WORDBREAKS" in
*:*) : great ;;
*) pfx="${cur%%:*}:" ;;
esac
cur="${cur#*:}"
lhs=0
;;
+*)
pfx="+"
cur="${cur#+}"
;;
esac
case "$cmd" in
fetch)
if [ $lhs = 1 ]; then
__gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur"
else
__gitcomp "$(__git_refs)" "$pfx" "$cur"
fi
;;
pull)
if [ $lhs = 1 ]; then
__gitcomp "$(__git_refs "$remote")" "$pfx" "$cur"
else
__gitcomp "$(__git_refs)" "$pfx" "$cur"
fi
;;
push)
if [ $lhs = 1 ]; then
__gitcomp "$(__git_refs)" "$pfx" "$cur"
else
__gitcomp "$(__git_refs "$remote")" "$pfx" "$cur"
fi
;;
esac
}
__git_complete_strategy ()
{
__git_compute_merge_strategies
case "${COMP_WORDS[COMP_CWORD-1]}" in
-s|--strategy)
__gitcomp "$__git_merge_strategies"
return 0
esac
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--strategy=*)
__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
return 0
;;
esac
return 1
}
__git_list_all_commands ()
{
local i IFS=" "$'\n'
for i in $(git help -a|egrep '^ [a-zA-Z0-9]')
do
case $i in
*--*) : helper pattern;;
*) echo $i;;
esac
done
}
__git_all_commands=
__git_compute_all_commands ()
{
: ${__git_all_commands:=$(__git_list_all_commands)}
}
__git_list_porcelain_commands ()
{
local i IFS=" "$'\n'
__git_compute_all_commands
for i in "help" $__git_all_commands
do
case $i in
*--*) : helper pattern;;
applymbox) : ask gittus;;
applypatch) : ask gittus;;
archimport) : import;;
cat-file) : plumbing;;
check-attr) : plumbing;;
check-ref-format) : plumbing;;
checkout-index) : plumbing;;
commit-tree) : plumbing;;
count-objects) : infrequent;;
cvsexportcommit) : export;;
cvsimport) : import;;
cvsserver) : daemon;;
daemon) : daemon;;
diff-files) : plumbing;;
diff-index) : plumbing;;
diff-tree) : plumbing;;
fast-import) : import;;
fast-export) : export;;
fsck-objects) : plumbing;;
fetch-pack) : plumbing;;
fmt-merge-msg) : plumbing;;
for-each-ref) : plumbing;;
hash-object) : plumbing;;
http-*) : transport;;
index-pack) : plumbing;;
init-db) : deprecated;;
local-fetch) : plumbing;;
lost-found) : infrequent;;
ls-files) : plumbing;;
ls-remote) : plumbing;;
ls-tree) : plumbing;;
mailinfo) : plumbing;;
mailsplit) : plumbing;;
merge-*) : plumbing;;
mktree) : plumbing;;
mktag) : plumbing;;
pack-objects) : plumbing;;
pack-redundant) : plumbing;;
pack-refs) : plumbing;;
parse-remote) : plumbing;;
patch-id) : plumbing;;
peek-remote) : plumbing;;
prune) : plumbing;;
prune-packed) : plumbing;;
quiltimport) : import;;
read-tree) : plumbing;;
receive-pack) : plumbing;;
reflog) : plumbing;;
remote-*) : transport;;
repo-config) : deprecated;;
rerere) : plumbing;;
rev-list) : plumbing;;
rev-parse) : plumbing;;
runstatus) : plumbing;;
sh-setup) : internal;;
shell) : daemon;;
show-ref) : plumbing;;
send-pack) : plumbing;;
show-index) : plumbing;;
ssh-*) : transport;;
stripspace) : plumbing;;
symbolic-ref) : plumbing;;
tar-tree) : deprecated;;
unpack-file) : plumbing;;
unpack-objects) : plumbing;;
update-index) : plumbing;;
update-ref) : plumbing;;
update-server-info) : daemon;;
upload-archive) : plumbing;;
upload-pack) : plumbing;;
write-tree) : plumbing;;
var) : infrequent;;
verify-pack) : infrequent;;
verify-tag) : plumbing;;
*) echo $i;;
esac
done
}
__git_porcelain_commands=
__git_compute_porcelain_commands ()
{
__git_compute_all_commands
: ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
}
__git_aliases ()
{
local i IFS=$'\n'
for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do
case "$i" in
alias.*)
i="${i#alias.}"
echo "${i/ */}"
;;
esac
done
}
# __git_aliased_command requires 1 argument
__git_aliased_command ()
{
local word cmdline=$(git --git-dir="$(__gitdir)" \
config --get "alias.$1")
for word in $cmdline; do
bash: improve aliased command recognition To support completion for aliases, the completion script tries to figure out which git command is invoked by an alias. Its implementation in __git_aliased_command() is rather straightforward: it returns the first word from the alias. For simple aliases starting with the git command (e.g. alias.last = cat-file commit HEAD) this gives the right results. Unfortunately, it does not work with shell command aliases, which can get rather complex, as illustrated by one of Junio's aliases: [alias] lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -" In this case the current implementation returns "!sh" as the aliased git command, which is obviosly wrong. The full parsing of a shell command alias like that in the completion code is clearly unfeasible. However, we can easily improve on aliased command recognition by eleminating stuff that is definitely not a git command: shell commands (anything starting with '!'), command line options (anything starting with '-'), environment variables (anything with a '=' in it), and git itself. This way the above alias would be handled correctly, and the completion script would correctly recognize "log" as the aliased git command. Of course, this solution is not perfect either, and could be fooled easily. It's not hard to construct an alias, in which a word does not match any of these filter patterns, but is still not a git command (e.g. by setting an environment variable to a value which contains spaces). It may even return false positives, when the output of a git command is piped into an other git command, and the second gets the command line options via $@, but options for the first one are offered. However, the following patches will enable the user to supply custom completion scripts for aliases, which can be used to remedy these problematic cases. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
case "$word" in
\!gitk|gitk)
echo "gitk"
return
;;
bash: improve aliased command recognition To support completion for aliases, the completion script tries to figure out which git command is invoked by an alias. Its implementation in __git_aliased_command() is rather straightforward: it returns the first word from the alias. For simple aliases starting with the git command (e.g. alias.last = cat-file commit HEAD) this gives the right results. Unfortunately, it does not work with shell command aliases, which can get rather complex, as illustrated by one of Junio's aliases: [alias] lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -" In this case the current implementation returns "!sh" as the aliased git command, which is obviosly wrong. The full parsing of a shell command alias like that in the completion code is clearly unfeasible. However, we can easily improve on aliased command recognition by eleminating stuff that is definitely not a git command: shell commands (anything starting with '!'), command line options (anything starting with '-'), environment variables (anything with a '=' in it), and git itself. This way the above alias would be handled correctly, and the completion script would correctly recognize "log" as the aliased git command. Of course, this solution is not perfect either, and could be fooled easily. It's not hard to construct an alias, in which a word does not match any of these filter patterns, but is still not a git command (e.g. by setting an environment variable to a value which contains spaces). It may even return false positives, when the output of a git command is piped into an other git command, and the second gets the command line options via $@, but options for the first one are offered. However, the following patches will enable the user to supply custom completion scripts for aliases, which can be used to remedy these problematic cases. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
\!*) : shell command alias ;;
-*) : option ;;
*=*) : setting env ;;
git) : git itself ;;
*)
echo "$word"
return
bash: improve aliased command recognition To support completion for aliases, the completion script tries to figure out which git command is invoked by an alias. Its implementation in __git_aliased_command() is rather straightforward: it returns the first word from the alias. For simple aliases starting with the git command (e.g. alias.last = cat-file commit HEAD) this gives the right results. Unfortunately, it does not work with shell command aliases, which can get rather complex, as illustrated by one of Junio's aliases: [alias] lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -" In this case the current implementation returns "!sh" as the aliased git command, which is obviosly wrong. The full parsing of a shell command alias like that in the completion code is clearly unfeasible. However, we can easily improve on aliased command recognition by eleminating stuff that is definitely not a git command: shell commands (anything starting with '!'), command line options (anything starting with '-'), environment variables (anything with a '=' in it), and git itself. This way the above alias would be handled correctly, and the completion script would correctly recognize "log" as the aliased git command. Of course, this solution is not perfect either, and could be fooled easily. It's not hard to construct an alias, in which a word does not match any of these filter patterns, but is still not a git command (e.g. by setting an environment variable to a value which contains spaces). It may even return false positives, when the output of a git command is piped into an other git command, and the second gets the command line options via $@, but options for the first one are offered. However, the following patches will enable the user to supply custom completion scripts for aliases, which can be used to remedy these problematic cases. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
esac
done
}
# __git_find_on_cmdline requires 1 argument
__git_find_on_cmdline ()
{
local word subcommand c=1
while [ $c -lt $COMP_CWORD ]; do
word="${COMP_WORDS[c]}"
for subcommand in $1; do
if [ "$subcommand" = "$word" ]; then
echo "$subcommand"
return
fi
done
c=$((++c))
done
}
__git_has_doubledash ()
{
local c=1
while [ $c -lt $COMP_CWORD ]; do
if [ "--" = "${COMP_WORDS[c]}" ]; then
return 0
fi
c=$((++c))
done
return 1
}
__git_whitespacelist="nowarn warn error error-all fix"
_git_am ()
{
local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
if [ -d "$dir"/rebase-apply ]; then
__gitcomp "--skip --continue --resolved --abort"
return
fi
case "$cur" in
--whitespace=*)
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
return
;;
--*)
__gitcomp "
--3way --committer-date-is-author-date --ignore-date
--ignore-whitespace --ignore-space-change
--interactive --keep --no-utf8 --signoff --utf8
--whitespace= --scissors
"
return
esac
COMPREPLY=()
}
_git_apply ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--whitespace=*)
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
return
;;
--*)
__gitcomp "
--stat --numstat --summary --check --index
--cached --index-info --reverse --reject --unidiff-zero
--apply --no-add --exclude=
--ignore-whitespace --ignore-space-change
--whitespace= --inaccurate-eof --verbose
"
return
esac
COMPREPLY=()
}
_git_add ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--interactive --refresh --patch --update --dry-run
--ignore-errors --intent-to-add
"
return
esac
COMPREPLY=()
}
_git_archive ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--format=*)
__gitcomp "$(git archive --list)" "" "${cur##--format=}"
return
;;
--remote=*)
__gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
return
;;
--*)
__gitcomp "
--format= --list --verbose
--prefix= --remote= --exec=
"
return
;;
esac
__git_complete_file
}
_git_bisect ()
{
__git_has_doubledash && return
local subcommands="start bad good skip reset visualize replay log run"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
fi
case "$subcommand" in
bad|good|reset|skip)
__gitcomp "$(__git_refs)"
;;
*)
COMPREPLY=()
;;
esac
}
_git_branch ()
{
local i c=1 only_local_ref="n" has_r="n"
while [ $c -lt $COMP_CWORD ]; do
i="${COMP_WORDS[c]}"
case "$i" in
-d|-m) only_local_ref="y" ;;
-r) has_r="y" ;;
esac
c=$((++c))
done
case "${COMP_WORDS[COMP_CWORD]}" in
--*)
__gitcomp "
--color --no-color --verbose --abbrev= --no-abbrev
--track --no-track --contains --merged --no-merged
--set-upstream
"
;;
*)
if [ $only_local_ref = "y" -a $has_r = "n" ]; then
__gitcomp "$(__git_heads)"
else
__gitcomp "$(__git_refs)"
fi
;;
esac
}
_git_bundle ()
{
local cmd="${COMP_WORDS[2]}"
case "$COMP_CWORD" in
2)
__gitcomp "create list-heads verify unbundle"
;;
3)
# looking for a file
;;
*)
case "$cmd" in
create)
__git_complete_revlist
;;
esac
;;
esac
}
_git_checkout ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--conflict=*)
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
;;
--*)
__gitcomp "
--quiet --ours --theirs --track --no-track --merge
--conflict= --patch
"
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
_git_cherry ()
{
__gitcomp "$(__git_refs)"
}
_git_cherry_pick ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--edit --no-commit"
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
_git_clean ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--dry-run --quiet"
return
;;
esac
COMPREPLY=()
}
_git_clone ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--local
--no-hardlinks
--shared
--reference
--quiet
--no-checkout
--bare
--mirror
--origin
--upload-pack
--template=
--depth
"
return
;;
esac
COMPREPLY=()
}
_git_commit ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--cleanup=*)
__gitcomp "default strip verbatim whitespace
" "" "${cur##--cleanup=}"
return
;;
--reuse-message=*)
__gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
return
;;
--reedit-message=*)
__gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
return
;;
--untracked-files=*)
__gitcomp "all no normal" "" "${cur##--untracked-files=}"
return
;;
--*)
__gitcomp "
--all --author= --signoff --verify --no-verify
--edit --amend --include --only --interactive
--dry-run --reuse-message= --reedit-message=
--reset-author --file= --message= --template=
--cleanup= --untracked-files --untracked-files=
--verbose --quiet
"
return
esac
COMPREPLY=()
}
_git_describe ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--all --tags --contains --abbrev= --candidates=
--exact-match --debug --long --match --always
"
return
esac
__gitcomp "$(__git_refs)"
}
__git_diff_common_options="--stat --numstat --shortstat --summary
--patch-with-stat --name-only --name-status --color
--no-color --color-words --no-renames --check
--full-index --binary --abbrev --diff-filter=
--find-copies-harder
--text --ignore-space-at-eol --ignore-space-change
--ignore-all-space --exit-code --quiet --ext-diff
--no-ext-diff
--no-prefix --src-prefix= --dst-prefix=
--inter-hunk-context=
--patience
--raw
--dirstat --dirstat= --dirstat-by-file
--dirstat-by-file= --cumulative
"
_git_diff ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
--base --ours --theirs
$__git_diff_common_options
"
return
;;
esac
__git_complete_file
}
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
tkdiff vimdiff gvimdiff xxdiff araxis p4merge
"
_git_difftool ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--tool=*)
__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
return
;;
--*)
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
--base --ours --theirs
--no-renames --diff-filter= --find-copies-harder
--relative --ignore-submodules
--tool="
return
;;
esac
__git_complete_file
}
__git_fetch_options="
--quiet --verbose --append --upload-pack --force --keep --depth=
--tags --no-tags --all --prune --dry-run
"
_git_fetch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "$__git_fetch_options"
return
;;
esac
__git_complete_remote_or_refspec
}
_git_format_patch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--thread=*)
__gitcomp "
deep shallow
" "" "${cur##--thread=}"
return
;;
--*)
__gitcomp "
--stdout --attach --no-attach --thread --thread=
--output-directory
--numbered --start-number
--numbered-files
--keep-subject
--signoff
--in-reply-to= --cc=
--full-index --binary
--not --all
--cover-letter
--no-prefix --src-prefix= --dst-prefix=
--inline --suffix= --ignore-if-in-upstream
--subject-prefix=
"
return
;;
esac
__git_complete_revlist
}
_git_fsck ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--tags --root --unreachable --cache --no-reflogs --full
--strict --verbose --lost-found
"
return
;;
esac
COMPREPLY=()
}
_git_gc ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--prune --aggressive"
return
;;
esac
COMPREPLY=()
}
_git_gitk ()
{
_gitk
}
_git_grep ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--cached
--text --ignore-case --word-regexp --invert-match
--full-name
--extended-regexp --basic-regexp --fixed-strings
--files-with-matches --name-only
--files-without-match
--max-depth
--count
--and --or --not --all-match
"
return
;;
esac
__gitcomp "$(__git_refs)"
}
_git_help ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--all --info --man --web"
return
;;
esac
__git_compute_all_commands
__gitcomp "$__git_all_commands
attributes cli core-tutorial cvs-migration
diffcore gitk glossary hooks ignore modules
repository-layout tutorial tutorial-2
workflows
"
}
_git_init ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--shared=*)
__gitcomp "
false true umask group all world everybody
" "" "${cur##--shared=}"
return
;;
--*)
__gitcomp "--quiet --bare --template= --shared --shared="
return
;;
esac
COMPREPLY=()
}
_git_ls_files ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--cached --deleted --modified --others --ignored
--stage --directory --no-empty-directory --unmerged
--killed --exclude= --exclude-from=
--exclude-per-directory= --exclude-standard
--error-unmatch --with-tree= --full-name
--abbrev --ignored --exclude-per-directory
"
return
;;
esac
COMPREPLY=()
}
_git_ls_remote ()
{
__gitcomp "$(__git_remotes)"
}
_git_ls_tree ()
{
__git_complete_file
}
# Options that go well for log, shortlog and gitk
__git_log_common_options="
--not --all
--branches --tags --remotes
--first-parent --merges --no-merges
--max-count=
--max-age= --since= --after=
--min-age= --until= --before=
"
# Options that go well for log and gitk (not shortlog)
__git_log_gitk_options="
--dense --sparse --full-history
--simplify-merges --simplify-by-decoration
--left-right
"
# Options that go well for log and shortlog (not gitk)
__git_log_shortlog_options="
--author= --committer= --grep=
--all-match
"
__git_log_pretty_formats="oneline short medium full fuller email raw format:"
__git_log_date_formats="relative iso8601 rfc2822 short local default raw"
_git_log ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
local g="$(git rev-parse --git-dir 2>/dev/null)"
local merge=""
if [ -f "$g/MERGE_HEAD" ]; then
merge="--merge"
fi
case "$cur" in
--pretty=*)
__gitcomp "$__git_log_pretty_formats
" "" "${cur##--pretty=}"
return
;;
--format=*)
__gitcomp "$__git_log_pretty_formats
" "" "${cur##--format=}"
return
;;
--date=*)
__gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
return
;;
--decorate=*)
__gitcomp "long short" "" "${cur##--decorate=}"
return
;;
--*)
__gitcomp "
$__git_log_common_options
$__git_log_shortlog_options
$__git_log_gitk_options
--root --topo-order --date-order --reverse
--follow --full-diff
--abbrev-commit --abbrev=
--relative-date --date=
--pretty= --format= --oneline
--cherry-pick
--graph
--decorate --decorate=
--walk-reflogs
--parents --children
$merge
$__git_diff_common_options
--pickaxe-all --pickaxe-regex
"
return
;;
esac
__git_complete_revlist
}
__git_merge_options="
--no-commit --no-stat --log --no-log --squash --strategy
--commit --stat --no-squash --ff --no-ff --ff-only
"
_git_merge ()
{
__git_complete_strategy && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "$__git_merge_options"
return
esac
__gitcomp "$(__git_refs)"
}
_git_mergetool ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--tool=*)
__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
return
;;
--*)
__gitcomp "--tool="
return
;;
esac
COMPREPLY=()
}
_git_merge_base ()
{
__gitcomp "$(__git_refs)"
}
_git_mv ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--dry-run"
return
;;
esac
COMPREPLY=()
}
_git_name_rev ()
{
__gitcomp "--tags --all --stdin"
}
_git_notes ()
{
local subcommands="edit show"
if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
__gitcomp "$subcommands"
return
fi
case "${COMP_WORDS[COMP_CWORD-1]}" in
-m|-F)
COMPREPLY=()
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
_git_pull ()
{
__git_complete_strategy && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--rebase --no-rebase
$__git_merge_options
$__git_fetch_options
"
return
;;
esac
__git_complete_remote_or_refspec
}
_git_push ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${COMP_WORDS[COMP_CWORD-1]}" in
--repo)
__gitcomp "$(__git_remotes)"
return
esac
case "$cur" in
--repo=*)
__gitcomp "$(__git_remotes)" "" "${cur##--repo=}"
return
;;
--*)
__gitcomp "
--all --mirror --tags --dry-run --force --verbose
--receive-pack= --repo=
"
return
;;
esac
__git_complete_remote_or_refspec
}
_git_rebase ()
{
local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
__gitcomp "--continue --skip --abort"
return
fi
__git_complete_strategy && return
case "$cur" in
--whitespace=*)
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
return
;;
--*)
__gitcomp "
--onto --merge --strategy --interactive
--preserve-merges --stat --no-stat
--committer-date-is-author-date --ignore-date
--ignore-whitespace --whitespace=
--autosquash
"
return
esac
__gitcomp "$(__git_refs)"
}
__git_send_email_confirm_options="always never auto cc compose"
__git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
_git_send_email ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--confirm=*)
__gitcomp "
$__git_send_email_confirm_options
" "" "${cur##--confirm=}"
return
;;
--suppress-cc=*)
__gitcomp "
$__git_send_email_suppresscc_options
" "" "${cur##--suppress-cc=}"
return
;;
--smtp-encryption=*)
__gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
return
;;
--*)
__gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
--compose --confirm= --dry-run --envelope-sender
--from --identity
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc
--no-suppress-from --no-thread --quiet
--signed-off-by-cc --smtp-pass --smtp-server
--smtp-server-port --smtp-encryption= --smtp-user
--subject --suppress-cc= --suppress-from --thread --to
--validate --no-validate"
return
;;
esac
COMPREPLY=()
}
bash: support user-supplied completion scripts for user's git commands The bash completion script already provides support to complete aliases, options and refs for aliases (if the alias can be traced back to a supported git command by __git_aliased_command()), and the user's custom git commands, but it does not support the options of the user's custom git commands (of course; how could it know about the options of a custom git command?). Users of such custom git commands could extend git's bash completion script by writing functions to support their commands, but they might have issues with it: they might not have the rights to modify a system-wide git completion script, and they will need to track and merge upstream changes in the future. This patch addresses this by providing means for users to supply custom completion scriplets for their custom git commands without modifying the main git bash completion script. Instead of having a huge hard-coded list of command-completion function pairs (in _git()), the completion script will figure out which completion function to call based on the command's name. That is, when completing the options of 'git foo', the main completion script will check whether the function '_git_foo' is declared, and if declared, it will invoke that function to perform the completion. If such a function is not declared, it will fall back to complete file names. So, users will only need to provide this '_git_foo' completion function in a separate file, source that file, and it will be used the next time they press TAB after 'git foo '. There are two git commands (stage and whatchanged), for which the completion functions of other commands were used, therefore they got their own completion function. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:58 +01:00
_git_stage ()
{
_git_add
}
__git_config_get_set_variables ()
{
local prevword word config_file= c=$COMP_CWORD
while [ $c -gt 1 ]; do
word="${COMP_WORDS[c]}"
case "$word" in
--global|--system|--file=*)
config_file="$word"
break
;;
-f|--file)
config_file="$word $prevword"
break
;;
esac
prevword=$word
c=$((--c))
done
git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null |
while read line
do
case "$line" in
*.*=*)
echo "${line/=*/}"
;;
esac
done
}
_git_config ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
local prv="${COMP_WORDS[COMP_CWORD-1]}"
case "$prv" in
branch.*.remote)
__gitcomp "$(__git_remotes)"
return
;;
branch.*.merge)
__gitcomp "$(__git_refs)"
return
;;
remote.*.fetch)
local remote="${prv#remote.}"
remote="${remote%.fetch}"
__gitcomp "$(__git_refs_remotes "$remote")"
return
;;
remote.*.push)
local remote="${prv#remote.}"
remote="${remote%.push}"
__gitcomp "$(git --git-dir="$(__gitdir)" \
for-each-ref --format='%(refname):%(refname)' \
refs/heads)"
return
;;
pull.twohead|pull.octopus)
__git_compute_merge_strategies
__gitcomp "$__git_merge_strategies"
return
;;
color.branch|color.diff|color.interactive|\
color.showbranch|color.status|color.ui)
__gitcomp "always never auto"
return
;;
color.pager)
__gitcomp "false true"
return
;;
color.*.*)
__gitcomp "
normal black red green yellow blue magenta cyan white
bold dim ul blink reverse
"
return
;;
help.format)
__gitcomp "man info web html"
return
;;
log.date)
__gitcomp "$__git_log_date_formats"
return
;;
sendemail.aliasesfiletype)
__gitcomp "mutt mailrc pine elm gnus"
return
;;
sendemail.confirm)
__gitcomp "$__git_send_email_confirm_options"
return
;;
sendemail.suppresscc)
__gitcomp "$__git_send_email_suppresscc_options"
return
;;
--get|--get-all|--unset|--unset-all)
__gitcomp "$(__git_config_get_set_variables)"
return
;;
*.*)
COMPREPLY=()
return
;;
esac
case "$cur" in
--*)
__gitcomp "
--global --system --file=
--list --replace-all
--get --get-all --get-regexp
--add --unset --unset-all
--remove-section --rename-section
"
return
;;
branch.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur"
return
;;
branch.*)
local pfx="${cur%.*}."
cur="${cur#*.}"
__gitcomp "$(__git_heads)" "$pfx" "$cur" "."
return
;;
guitool.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "
argprompt cmd confirm needsfile noconsole norescan
prompt revprompt revunmerged title
" "$pfx" "$cur"
return
;;
difftool.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "cmd path" "$pfx" "$cur"
return
;;
man.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "cmd path" "$pfx" "$cur"
return
;;
mergetool.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "cmd path trustExitCode" "$pfx" "$cur"
return
;;
pager.*)
local pfx="${cur%.*}."
cur="${cur#*.}"
__git_compute_all_commands
__gitcomp "$__git_all_commands" "$pfx" "$cur"
return
;;
remote.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "
url proxy fetch push mirror skipDefaultUpdate
receivepack uploadpack tagopt pushurl
" "$pfx" "$cur"
return
;;
remote.*)
local pfx="${cur%.*}."
cur="${cur#*.}"
__gitcomp "$(__git_remotes)" "$pfx" "$cur" "."
return
;;
url.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur"
return
;;
esac
__gitcomp "
add.ignore-errors
alias.
apply.ignorewhitespace
apply.whitespace
branch.autosetupmerge
branch.autosetuprebase
clean.requireForce
color.branch
color.branch.current
color.branch.local
color.branch.plain
color.branch.remote
color.diff
color.diff.commit
color.diff.frag
color.diff.meta
color.diff.new
color.diff.old
color.diff.plain
color.diff.whitespace
color.grep
color.grep.external
color.grep.match
color.interactive
color.interactive.header
color.interactive.help
color.interactive.prompt
color.pager
color.showbranch
color.status
color.status.added
color.status.changed
color.status.header
color.status.nobranch
color.status.untracked
color.status.updated
color.ui
commit.template
core.autocrlf
core.bare
core.compression
core.createObject
core.deltaBaseCacheLimit
core.editor
core.excludesfile
core.fileMode
core.fsyncobjectfiles
core.gitProxy
core.ignoreCygwinFSTricks
core.ignoreStat
core.logAllRefUpdates
core.loosecompression
core.packedGitLimit
core.packedGitWindowSize
core.pager
core.preferSymlinkRefs
core.preloadindex
core.quotepath
core.repositoryFormatVersion
core.safecrlf
core.sharedRepository
core.symlinks
core.trustctime
core.warnAmbiguousRefs
core.whitespace
core.worktree
diff.autorefreshindex
diff.external
diff.mnemonicprefix
diff.renameLimit
diff.renameLimit.
diff.renames
diff.suppressBlankEmpty
diff.tool
diff.wordRegex
difftool.
difftool.prompt
fetch.unpackLimit
format.attach
format.cc
format.headers
format.numbered
format.pretty
format.signoff
format.subjectprefix
format.suffix
format.thread
gc.aggressiveWindow
gc.auto
gc.autopacklimit
gc.packrefs
gc.pruneexpire
gc.reflogexpire
gc.reflogexpireunreachable
gc.rerereresolved
gc.rerereunresolved
gitcvs.allbinary
gitcvs.commitmsgannotation
gitcvs.dbTableNamePrefix
gitcvs.dbdriver
gitcvs.dbname
gitcvs.dbpass
gitcvs.dbuser
gitcvs.enabled
gitcvs.logfile
gitcvs.usecrlfattr
guitool.
gui.blamehistoryctx
gui.commitmsgwidth
gui.copyblamethreshold
gui.diffcontext
gui.encoding
gui.fastcopyblame
gui.matchtrackingbranch
gui.newbranchtemplate
gui.pruneduringfetch
gui.spellingdictionary
gui.trustmtime
help.autocorrect
help.browser
help.format
http.lowSpeedLimit
http.lowSpeedTime
http.maxRequests
http.noEPSV
http.proxy
http.sslCAInfo
http.sslCAPath
http.sslCert
http.sslKey
http.sslVerify
i18n.commitEncoding
i18n.logOutputEncoding
imap.folder
imap.host
imap.pass
imap.port
imap.preformattedHTML
imap.sslverify
imap.tunnel
imap.user
instaweb.browser
instaweb.httpd
instaweb.local
instaweb.modulepath
instaweb.port
interactive.singlekey
log.date
log.showroot
mailmap.file
man.
man.viewer
merge.conflictstyle
merge.log
merge.renameLimit
merge.stat
merge.tool
merge.verbosity
mergetool.
mergetool.keepBackup
mergetool.prompt
pack.compression
pack.deltaCacheLimit
pack.deltaCacheSize
pack.depth
pack.indexVersion
pack.packSizeLimit
pack.threads
pack.window
pack.windowMemory
pager.
pull.octopus
pull.twohead
push.default
rebase.stat
receive.denyCurrentBranch
receive.denyDeletes
receive.denyNonFastForwards
receive.fsckObjects
receive.unpackLimit
repack.usedeltabaseoffset
rerere.autoupdate
rerere.enabled
sendemail.aliasesfile
sendemail.aliasesfiletype
sendemail.bcc
sendemail.cc
sendemail.cccmd
sendemail.chainreplyto
sendemail.confirm
sendemail.envelopesender
sendemail.multiedit
sendemail.signedoffbycc
sendemail.smtpencryption
sendemail.smtppass
sendemail.smtpserver
sendemail.smtpserverport
sendemail.smtpuser
sendemail.suppresscc
sendemail.suppressfrom
sendemail.thread
sendemail.to
sendemail.validate
showbranch.default
status.relativePaths
status.showUntrackedFiles
tar.umask
transfer.unpackLimit
url.
user.email
user.name
user.signingkey
web.browser
branch. remote.
"
}
_git_remote ()
{
local subcommands="add rename rm show prune update set-head"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
fi
case "$subcommand" in
rename|rm|show|prune)
__gitcomp "$(__git_remotes)"
;;
update)
local i c='' IFS=$'\n'
for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do
i="${i#remotes.}"
c="$c ${i/ */}"
done
__gitcomp "$c"
;;
*)
COMPREPLY=()
;;
esac
}
_git_replace ()
{
__gitcomp "$(__git_refs)"
}
_git_reset ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--merge --mixed --hard --soft --patch"
return
;;
esac
__gitcomp "$(__git_refs)"
}
_git_revert ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--edit --mainline --no-edit --no-commit --signoff"
return
;;
esac
__gitcomp "$(__git_refs)"
}
_git_rm ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
return
;;
esac
COMPREPLY=()
}
_git_shortlog ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
$__git_log_common_options
$__git_log_shortlog_options
--numbered --summary
"
return
;;
esac
__git_complete_revlist
}
_git_show ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--pretty=*)
__gitcomp "$__git_log_pretty_formats
" "" "${cur##--pretty=}"
return
;;
--format=*)
__gitcomp "$__git_log_pretty_formats
" "" "${cur##--format=}"
return
;;
--*)
__gitcomp "--pretty= --format= --abbrev-commit --oneline
$__git_diff_common_options
"
return
;;
esac
__git_complete_file
}
_git_show_branch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--all --remotes --topo-order --current --more=
--list --independent --merge-base --no-name
--color --no-color
--sha1-name --sparse --topics --reflog
"
return
;;
esac
__git_complete_revlist
}
_git_stash ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
local save_opts='--keep-index --no-keep-index --quiet --patch'
local subcommands='save list show apply clear drop pop create branch'
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
case "$cur" in
--*)
__gitcomp "$save_opts"
;;
*)
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
__gitcomp "$subcommands"
else
COMPREPLY=()
fi
;;
esac
else
case "$subcommand,$cur" in
save,--*)
__gitcomp "$save_opts"
;;
apply,--*|pop,--*)
__gitcomp "--index --quiet"
;;
show,--*|drop,--*|branch,--*)
COMPREPLY=()
;;
show,*|apply,*|drop,*|pop,*|branch,*)
__gitcomp "$(git --git-dir="$(__gitdir)" stash list \
| sed -n -e 's/:.*//p')"
;;
*)
COMPREPLY=()
;;
esac
fi
}
_git_submodule ()
{
__git_has_doubledash && return
local subcommands="add status init update summary foreach sync"
if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--quiet --cached"
;;
*)
__gitcomp "$subcommands"
;;
esac
return
fi
}
_git_svn ()
{
local subcommands="
init fetch clone rebase dcommit log find-rev
set-tree commit-diff info create-ignore propget
proplist show-ignore show-externals branch tag blame
migrate mkdirs reset gc
"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
else
local remote_opts="--username= --config-dir= --no-auth-cache"
local fc_opts="
--follow-parent --authors-file= --repack=
--no-metadata --use-svm-props --use-svnsync-props
--log-window-size= --no-checkout --quiet
--repack-flags --use-log-author --localtime
--ignore-paths= $remote_opts
"
local init_opts="
--template= --shared= --trunk= --tags=
--branches= --stdlayout --minimize-url
--no-metadata --use-svm-props --use-svnsync-props
--rewrite-root= --prefix= --use-log-author
--add-author-from $remote_opts
"
local cmt_opts="
--edit --rmdir --find-copies-harder --copy-similarity=
"
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$subcommand,$cur" in
fetch,--*)
__gitcomp "--revision= --fetch-all $fc_opts"
;;
clone,--*)
__gitcomp "--revision= $fc_opts $init_opts"
;;
init,--*)
__gitcomp "$init_opts"
;;
dcommit,--*)
__gitcomp "
--merge --strategy= --verbose --dry-run
--fetch-all --no-rebase --commit-url
--revision $cmt_opts $fc_opts
"
;;
set-tree,--*)
__gitcomp "--stdin $cmt_opts $fc_opts"
;;
create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\
show-externals,--*|mkdirs,--*)
__gitcomp "--revision="
;;
log,--*)
__gitcomp "
--limit= --revision= --verbose --incremental
--oneline --show-commit --non-recursive
--authors-file= --color
"
;;
rebase,--*)
__gitcomp "
--merge --verbose --strategy= --local
--fetch-all --dry-run $fc_opts
"
;;
commit-diff,--*)
__gitcomp "--message= --file= --revision= $cmt_opts"
;;
info,--*)
__gitcomp "--url"
;;
branch,--*)
__gitcomp "--dry-run --message --tag"
;;
tag,--*)
__gitcomp "--dry-run --message"
;;
blame,--*)
__gitcomp "--git-format"
;;
migrate,--*)
__gitcomp "
--config-dir= --ignore-paths= --minimize
--no-auth-cache --username=
"
;;
reset,--*)
__gitcomp "--revision= --parent"
;;
*)
COMPREPLY=()
;;
esac
fi
}
_git_tag ()
{
local i c=1 f=0
while [ $c -lt $COMP_CWORD ]; do
i="${COMP_WORDS[c]}"
case "$i" in
-d|-v)
__gitcomp "$(__git_tags)"
return
;;
-f)
f=1
;;
esac
c=$((++c))
done
case "${COMP_WORDS[COMP_CWORD-1]}" in
-m|-F)
COMPREPLY=()
;;
-*|tag)
if [ $f = 1 ]; then
__gitcomp "$(__git_tags)"
else
COMPREPLY=()
fi
;;
*)
__gitcomp "$(__git_refs)"
;;
esac
}
bash: support user-supplied completion scripts for user's git commands The bash completion script already provides support to complete aliases, options and refs for aliases (if the alias can be traced back to a supported git command by __git_aliased_command()), and the user's custom git commands, but it does not support the options of the user's custom git commands (of course; how could it know about the options of a custom git command?). Users of such custom git commands could extend git's bash completion script by writing functions to support their commands, but they might have issues with it: they might not have the rights to modify a system-wide git completion script, and they will need to track and merge upstream changes in the future. This patch addresses this by providing means for users to supply custom completion scriplets for their custom git commands without modifying the main git bash completion script. Instead of having a huge hard-coded list of command-completion function pairs (in _git()), the completion script will figure out which completion function to call based on the command's name. That is, when completing the options of 'git foo', the main completion script will check whether the function '_git_foo' is declared, and if declared, it will invoke that function to perform the completion. If such a function is not declared, it will fall back to complete file names. So, users will only need to provide this '_git_foo' completion function in a separate file, source that file, and it will be used the next time they press TAB after 'git foo '. There are two git commands (stage and whatchanged), for which the completion functions of other commands were used, therefore they got their own completion function. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:58 +01:00
_git_whatchanged ()
{
_git_log
}
_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|-p|--paginate) ;;
--help) command="help"; break ;;
*) command="$i"; break ;;
esac
c=$((++c))
done
if [ -z "$command" ]; then
case "${COMP_WORDS[COMP_CWORD]}" in
--*) __gitcomp "
--paginate
--no-pager
--git-dir=
--bare
--version
--exec-path
--html-path
--work-tree=
--help
"
;;
*) __git_compute_porcelain_commands
__gitcomp "$__git_porcelain_commands $(__git_aliases)" ;;
esac
return
fi
bash: support user-supplied completion scripts for user's git commands The bash completion script already provides support to complete aliases, options and refs for aliases (if the alias can be traced back to a supported git command by __git_aliased_command()), and the user's custom git commands, but it does not support the options of the user's custom git commands (of course; how could it know about the options of a custom git command?). Users of such custom git commands could extend git's bash completion script by writing functions to support their commands, but they might have issues with it: they might not have the rights to modify a system-wide git completion script, and they will need to track and merge upstream changes in the future. This patch addresses this by providing means for users to supply custom completion scriplets for their custom git commands without modifying the main git bash completion script. Instead of having a huge hard-coded list of command-completion function pairs (in _git()), the completion script will figure out which completion function to call based on the command's name. That is, when completing the options of 'git foo', the main completion script will check whether the function '_git_foo' is declared, and if declared, it will invoke that function to perform the completion. If such a function is not declared, it will fall back to complete file names. So, users will only need to provide this '_git_foo' completion function in a separate file, source that file, and it will be used the next time they press TAB after 'git foo '. There are two git commands (stage and whatchanged), for which the completion functions of other commands were used, therefore they got their own completion function. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:58 +01:00
local completion_func="_git_${command//-/_}"
2010-02-23 22:02:59 +01:00
declare -F $completion_func >/dev/null && $completion_func && return
local expansion=$(__git_aliased_command "$command")
2010-02-23 22:02:59 +01:00
if [ -n "$expansion" ]; then
completion_func="_git_${expansion//-/_}"
declare -F $completion_func >/dev/null && $completion_func
fi
}
_gitk ()
{
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
local g="$(__gitdir)"
local merge=""
if [ -f "$g/MERGE_HEAD" ]; then
merge="--merge"
fi
case "$cur" in
--*)
__gitcomp "
$__git_log_common_options
$__git_log_gitk_options
$merge
"
return
;;
esac
__git_complete_revlist
}
complete -o bashdefault -o default -o nospace -F _git git 2>/dev/null \
|| complete -o default -o nospace -F _git git
complete -o bashdefault -o default -o nospace -F _gitk gitk 2>/dev/null \
|| complete -o default -o nospace -F _gitk gitk
# 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 bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
|| complete -o default -o nospace -F _git git.exe
fi