summaryrefslogtreecommitdiff
path: root/contrib/completion
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/completion')
-rw-r--r--contrib/completion/git-completion.bash62
-rw-r--r--contrib/completion/git-completion.zsh1
-rw-r--r--contrib/completion/git-prompt.sh77
3 files changed, 129 insertions, 11 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 9525343fcd..06bf262087 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,12 @@
# source ~/.git-completion.sh
# 3) Consider changing your PS1 to also show the current branch,
# see git-prompt.sh for details.
+#
+# 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 ; ... '".
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -781,6 +787,10 @@ __git_aliased_command ()
-*) : option ;;
*=*) : setting env ;;
git) : git itself ;;
+ \(\)) : skip parens of shell function definition ;;
+ {) : skip start of shell helper function ;;
+ :) : skip null command ;;
+ \'*) : skip opening quote after sh -c ;;
*)
echo "$word"
return
@@ -1221,14 +1231,20 @@ _git_difftool ()
__git_complete_revlist_file
}
+__git_fetch_recurse_submodules="yes on-demand no"
+
__git_fetch_options="
--quiet --verbose --append --upload-pack --force --keep --depth=
- --tags --no-tags --all --prune --dry-run
+ --tags --no-tags --all --prune --dry-run --recurse-submodules=
"
_git_fetch ()
{
case "$cur" in
+ --recurse-submodules=*)
+ __gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}"
+ return
+ ;;
--*)
__gitcomp "$__git_fetch_options"
return
@@ -1466,9 +1482,12 @@ _git_log ()
__git_complete_revlist
}
+# Common merge options shared by git-merge(1) and git-pull(1).
__git_merge_options="
--no-commit --no-stat --log --no-log --squash --strategy
--commit --stat --no-squash --ff --no-ff --ff-only --edit --no-edit
+ --verify-signatures --no-verify-signatures --gpg-sign
+ --quiet --verbose --progress --no-progress
"
_git_merge ()
@@ -1477,7 +1496,8 @@ _git_merge ()
case "$cur" in
--*)
- __gitcomp "$__git_merge_options"
+ __gitcomp "$__git_merge_options
+ --rerere-autoupdate --no-rerere-autoupdate --abort"
return
esac
__gitcomp_nl "$(__git_refs)"
@@ -1583,6 +1603,10 @@ _git_pull ()
__git_complete_strategy && return
case "$cur" in
+ --recurse-submodules=*)
+ __gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}"
+ return
+ ;;
--*)
__gitcomp "
--rebase --no-rebase
@@ -1595,22 +1619,55 @@ _git_pull ()
__git_complete_remote_or_refspec
}
+__git_push_recurse_submodules="check on-demand"
+
+__git_complete_force_with_lease ()
+{
+ local cur_=$1
+
+ case "$cur_" in
+ --*=)
+ ;;
+ *:*)
+ __gitcomp_nl "$(__git_refs)" "" "${cur_#*:}"
+ ;;
+ *)
+ __gitcomp_nl "$(__git_refs)" "" "$cur_"
+ ;;
+ esac
+}
+
_git_push ()
{
case "$prev" in
--repo)
__gitcomp_nl "$(__git_remotes)"
return
+ ;;
+ --recurse-submodules)
+ __gitcomp "$__git_push_recurse_submodules"
+ return
+ ;;
esac
case "$cur" in
--repo=*)
__gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}"
return
;;
+ --recurse-submodules=*)
+ __gitcomp "$__git_push_recurse_submodules" "" "${cur##--recurse-submodules=}"
+ return
+ ;;
+ --force-with-lease=*)
+ __git_complete_force_with_lease "${cur##--force-with-lease=}"
+ return
+ ;;
--*)
__gitcomp "
--all --mirror --tags --dry-run --force --verbose
+ --quiet --prune --delete --follow-tags
--receive-pack= --repo= --set-upstream
+ --force-with-lease --force-with-lease= --recurse-submodules=
"
return
;;
@@ -2547,6 +2604,7 @@ __git_main ()
local expansion=$(__git_aliased_command "$command")
if [ -n "$expansion" ]; then
+ words[1]=$expansion
completion_func="_git_${expansion//-/_}"
declare -f $completion_func >/dev/null && $completion_func
fi
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index 6b77968572..9f6f0fa558 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -104,6 +104,7 @@ __git_zsh_bash_func ()
local expansion=$(__git_aliased_command "$command")
if [ -n "$expansion" ]; then
+ words[1]=$expansion
completion_func="_git_${expansion//-/_}"
declare -f $completion_func >/dev/null && $completion_func
fi
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 7b732d2aeb..9d684b10a6 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -207,7 +207,16 @@ __git_ps1_show_upstream ()
p=" u+${count#* }-${count% *}" ;;
esac
if [[ -n "$count" && -n "$name" ]]; then
- p="$p $(git rev-parse --abbrev-ref "$upstream" 2>/dev/null)"
+ __git_ps1_upstream_name=$(git rev-parse \
+ --abbrev-ref "$upstream" 2>/dev/null)
+ if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ p="$p \${__git_ps1_upstream_name}"
+ else
+ p="$p ${__git_ps1_upstream_name}"
+ # not needed anymore; keep user's
+ # environment clean
+ unset __git_ps1_upstream_name
+ fi
fi
fi
@@ -259,6 +268,13 @@ __git_ps1_colorize_gitstring ()
r="$c_clear$r"
}
+__git_eread ()
+{
+ f="$1"
+ shift
+ test -r "$f" && read "$@" <"$f"
+}
+
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# when called from PS1 using command substitution
# in this mode it prints text to add to bash PS1 prompt (includes branch name)
@@ -290,6 +306,43 @@ __git_ps1 ()
;;
esac
+ # ps1_expanded: This variable is set to 'yes' if the shell
+ # subjects the value of PS1 to parameter expansion:
+ #
+ # * bash does unless the promptvars option is disabled
+ # * zsh does not unless the PROMPT_SUBST option is set
+ # * POSIX shells always do
+ #
+ # If the shell would expand the contents of PS1 when drawing
+ # the prompt, a raw ref name must not be included in PS1.
+ # This protects the user from arbitrary code execution via
+ # specially crafted ref names. For example, a ref named
+ # 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the
+ # shell to execute 'sudo rm -rf /' when the prompt is drawn.
+ #
+ # Instead, the ref name should be placed in a separate global
+ # variable (in the __git_ps1_* namespace to avoid colliding
+ # with the user's environment) and that variable should be
+ # referenced from PS1. For example:
+ #
+ # __git_ps1_foo=$(do_something_to_get_ref_name)
+ # PS1="...stuff...\${__git_ps1_foo}...stuff..."
+ #
+ # If the shell does not expand the contents of PS1, the raw
+ # ref name must be included in PS1.
+ #
+ # The value of this variable is only relevant when in pcmode.
+ #
+ # Assume that the shell follows the POSIX specification and
+ # expands PS1 unless determined otherwise. (This is more
+ # likely to be correct if the user has a non-bash, non-zsh
+ # shell and safer than the alternative if the assumption is
+ # incorrect.)
+ #
+ local ps1_expanded=yes
+ [ -z "$ZSH_VERSION" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+ [ -z "$BASH_VERSION" ] || shopt -q promptvars || ps1_expanded=no
+
local repo_info rev_parse_exit_code
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
--is-bare-repository --is-inside-work-tree \
@@ -321,9 +374,9 @@ __git_ps1 ()
local step=""
local total=""
if [ -d "$g/rebase-merge" ]; then
- read b 2>/dev/null <"$g/rebase-merge/head-name"
- read step 2>/dev/null <"$g/rebase-merge/msgnum"
- read total 2>/dev/null <"$g/rebase-merge/end"
+ __git_eread "$g/rebase-merge/head-name" b
+ __git_eread "$g/rebase-merge/msgnum" step
+ __git_eread "$g/rebase-merge/end" total
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
else
@@ -331,10 +384,10 @@ __git_ps1 ()
fi
else
if [ -d "$g/rebase-apply" ]; then
- read step 2>/dev/null <"$g/rebase-apply/next"
- read total 2>/dev/null <"$g/rebase-apply/last"
+ __git_eread "$g/rebase-apply/next" step
+ __git_eread "$g/rebase-apply/last" total
if [ -f "$g/rebase-apply/rebasing" ]; then
- read b 2>/dev/null <"$g/rebase-apply/head-name"
+ __git_eread "$g/rebase-apply/head-name" b
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
@@ -358,7 +411,7 @@ __git_ps1 ()
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
local head=""
- if ! read head 2>/dev/null <"$g/HEAD"; then
+ if ! __git_eread "$g/HEAD" head; then
if [ $pcmode = yes ]; then
PS1="$ps1pc_start$ps1pc_end"
fi
@@ -438,8 +491,14 @@ __git_ps1 ()
__git_ps1_colorize_gitstring
fi
+ b=${b##refs/heads/}
+ if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ __git_ps1_branch_name=$b
+ b="\${__git_ps1_branch_name}"
+ fi
+
local f="$w$i$s$u"
- local gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
+ local gitstring="$c$b${f:+$z$f}$r$p"
if [ $pcmode = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then