diff options
Diffstat (limited to 'contrib/completion')
-rw-r--r-- | contrib/completion/git-completion.bash | 130 | ||||
-rw-r--r-- | contrib/completion/git-completion.tcsh | 2 | ||||
-rw-r--r-- | contrib/completion/git-completion.zsh | 11 | ||||
-rw-r--r-- | contrib/completion/git-prompt.sh | 80 |
4 files changed, 182 insertions, 41 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index dba3c15700..2fece98c60 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1,5 +1,3 @@ -#!bash -# # bash/zsh completion support for core Git. # # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> @@ -23,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 ;; @@ -180,9 +184,9 @@ _get_comp_words_by_ref () } fi -__gitcompadd () +__gitcompappend () { - local i=0 + local i=${#COMPREPLY[@]} for x in $1; do if [[ "$x" == "$3"* ]]; then COMPREPLY[i++]="$2$x$4" @@ -190,6 +194,12 @@ __gitcompadd () done } +__gitcompadd () +{ + COMPREPLY=() + __gitcompappend "$@" +} + # Generates completion reply, appending a space to possible completion words, # if necessary. # It accepts 1 to 4 arguments: @@ -220,6 +230,14 @@ __gitcomp () esac } +# Variation of __gitcomp_nl () that appends to the existing list of +# completion candidates, COMPREPLY. +__gitcomp_nl_append () +{ + local IFS=$'\n' + __gitcompappend "$1" "${2-}" "${3-$cur}" "${4- }" +} + # Generates completion reply from newline-separated possible completion words # by appending a space to all of them. # It accepts 1 to 4 arguments: @@ -231,8 +249,8 @@ __gitcomp () # appended. __gitcomp_nl () { - local IFS=$'\n' - __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" + COMPREPLY=() + __gitcomp_nl_append "$@" } # Generates completion reply with compgen from newline-separated possible @@ -263,16 +281,12 @@ __gitcomp_file () # argument, and using the options specified in the second argument. __git_ls_files_helper () { - ( - test -n "${CDPATH+set}" && unset CDPATH - cd "$1" - if [ "$2" == "--committable" ]; then - git diff-index --name-only --relative HEAD - else - # NOTE: $2 is not quoted in order to support multiple options - git ls-files --exclude-standard $2 - fi - ) 2>/dev/null + if [ "$2" == "--committable" ]; then + git -C "$1" diff-index --name-only --relative HEAD + else + # NOTE: $2 is not quoted in order to support multiple options + git -C "$1" ls-files --exclude-standard $2 + fi 2>/dev/null } @@ -370,7 +384,8 @@ __git_refs () ;; *) echo "HEAD" - git for-each-ref --format="%(refname:short)" -- "refs/remotes/$dir/" | sed -e "s#^$dir/##" + git for-each-ref --format="%(refname:short)" -- \ + "refs/remotes/$dir/" 2>/dev/null | sed -e "s#^$dir/##" ;; esac } @@ -504,7 +519,7 @@ __git_complete_index_file () ;; esac - __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_" + __gitcomp_file "$(__git_index_files "$1" ${pfx:+"$pfx"})" "$pfx" "$cur_" } __git_complete_file () @@ -673,7 +688,6 @@ __git_list_porcelain_commands () index-pack) : plumbing;; init-db) : deprecated;; local-fetch) : plumbing;; - lost-found) : infrequent;; ls-files) : plumbing;; ls-remote) : plumbing;; ls-tree) : plumbing;; @@ -687,14 +701,12 @@ __git_list_porcelain_commands () 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;; remote-*) : transport;; - repo-config) : deprecated;; rerere) : plumbing;; rev-list) : plumbing;; rev-parse) : plumbing;; @@ -707,7 +719,6 @@ __git_list_porcelain_commands () ssh-*) : transport;; stripspace) : plumbing;; symbolic-ref) : plumbing;; - tar-tree) : deprecated;; unpack-file) : plumbing;; unpack-objects) : plumbing;; update-index) : plumbing;; @@ -773,6 +784,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 @@ -1157,8 +1172,8 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --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 + --ignore-all-space --ignore-blank-lines --exit-code + --quiet --ext-diff --no-ext-diff --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= --patience --histogram --minimal @@ -1189,7 +1204,7 @@ _git_diff () } __git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc codecompare " _git_difftool () @@ -1213,14 +1228,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 @@ -1443,6 +1464,7 @@ _git_log () --abbrev-commit --abbrev= --relative-date --date= --pretty= --format= --oneline + --show-signature --cherry-pick --graph --decorate --decorate= @@ -1458,9 +1480,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 () @@ -1469,7 +1494,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)" @@ -1491,6 +1517,12 @@ _git_mergetool () _git_merge_base () { + case "$cur" in + --*) + __gitcomp "--octopus --independent --is-ancestor --fork-point" + return + ;; + esac __gitcomp_nl "$(__git_refs)" } @@ -1569,6 +1601,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 @@ -1581,22 +1617,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 ;; @@ -1623,7 +1692,7 @@ _git_rebase () --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= - --autosquash + --autosquash --fork-point --no-fork-point " return @@ -1833,6 +1902,7 @@ _git_config () branch.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "." + __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_" return ;; guitool.*.*) @@ -1875,6 +1945,7 @@ _git_config () remote.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." + __gitcomp_nl_append "pushdefault" "$pfx" "$cur_" return ;; url.*.*) @@ -1997,6 +2068,7 @@ _git_config () fetch.unpackLimit format.attach format.cc + format.coverLetter format.headers format.numbered format.pretty @@ -2270,6 +2342,7 @@ _git_show () ;; --*) __gitcomp "--pretty= --format= --abbrev-commit --oneline + --show-signature $__git_diff_common_options " return @@ -2530,6 +2603,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.tcsh b/contrib/completion/git-completion.tcsh index eaacaf0c3e..6104a42a23 100644 --- a/contrib/completion/git-completion.tcsh +++ b/contrib/completion/git-completion.tcsh @@ -1,5 +1,3 @@ -#!tcsh -# # tcsh completion support for core Git. # # Copyright (C) 2012 Marc Khouzam <marc.khouzam@gmail.com> diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index fac5e711eb..9f6f0fa558 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -30,10 +30,10 @@ if [ -z "$script" ]; then local -a locations local e locations=( + $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash '/etc/bash_completion.d/git' # fedora, old debian '/usr/share/bash-completion/completions/git' # arch, ubuntu, new debian '/usr/share/bash-completion/git' # gentoo - $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash ) for e in $locations; do test -f $e && script="$e" && break @@ -76,6 +76,14 @@ __gitcomp_nl () compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 } +__gitcomp_nl_append () +{ + emulate -L zsh + + local IFS=$'\n' + compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 +} + __gitcomp_file () { emulate -L zsh @@ -96,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..c5473dc8db 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 @@ -415,7 +468,8 @@ __git_ps1 () fi fi if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] && - [ -r "$g/refs/stash" ]; then + git rev-parse --verify --quiet refs/stash >/dev/null + then s="$" fi @@ -438,8 +492,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 |