diff options
Diffstat (limited to 'contrib/completion/git-completion.bash')
-rw-r--r--[-rwxr-xr-x] | contrib/completion/git-completion.bash | 843 |
1 files changed, 399 insertions, 444 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 0acbdda3b..dba3c1570 100755..100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -13,6 +13,7 @@ # *) .git/remotes file names # *) git 'subcommands' # *) tree paths within 'ref:path/to/file' expressions +# *) file paths within current working directory and index # *) common --long-options # # To use these routines: @@ -20,50 +21,8 @@ # 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). # 2) Add the following line to your .bashrc/.zshrc: # source ~/.git-completion.sh -# -# 3) Consider changing your PS1 to also show the current branch: -# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' -# ZSH: PS1='[%n@%m %c$(__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. -# -# If you would like to see the difference between HEAD and its -# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates -# you are behind, ">" indicates you are ahead, and "<>" -# indicates you have diverged. You can further control -# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated -# list of values: -# verbose show number of commits ahead/behind (+/-) upstream -# legacy don't use the '--count' option available in recent -# versions of git-rev-list -# git always compare HEAD to @{upstream} -# svn always compare HEAD to your SVN upstream -# By default, __git_ps1 will compare HEAD to your SVN upstream -# if it can find one, or @{upstream} otherwise. Once you have -# set GIT_PS1_SHOWUPSTREAM, you can override it on a -# per-repository basis by setting the bash.showUpstream config -# variable. -# - -if [[ -n ${ZSH_VERSION-} ]]; then - autoload -U +X bashcompinit && bashcompinit -fi +# 3) Consider changing your PS1 to also show the current branch, +# see git-prompt.sh for details. case "$COMP_WORDBREAKS" in *:*) : great ;; @@ -77,6 +36,9 @@ __gitdir () if [ -z "${1-}" ]; then if [ -n "${__git_dir-}" ]; then echo "$__git_dir" + elif [ -n "${GIT_DIR-}" ]; then + test -d "${GIT_DIR-}" || return 1 + echo "$GIT_DIR" elif [ -d .git ]; then echo .git else @@ -89,235 +51,6 @@ __gitdir () fi } -# stores the divergence from upstream in $p -# used by GIT_PS1_SHOWUPSTREAM -__git_ps1_show_upstream () -{ - local key value - local svn_remote=() svn_url_pattern count n - local upstream=git legacy="" verbose="" - - # get some config options from git-config - local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')" - while read -r key value; do - case "$key" in - bash.showupstream) - GIT_PS1_SHOWUPSTREAM="$value" - if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then - p="" - return - fi - ;; - svn-remote.*.url) - svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value" - svn_url_pattern+="\\|$value" - upstream=svn+git # default upstream is SVN if available, else git - ;; - esac - done <<< "$output" - - # parse configuration values - for option in ${GIT_PS1_SHOWUPSTREAM}; do - case "$option" in - git|svn) upstream="$option" ;; - verbose) verbose=1 ;; - legacy) legacy=1 ;; - esac - done - - # Find our upstream - case "$upstream" in - git) upstream="@{upstream}" ;; - svn*) - # get the upstream from the "git-svn-id: ..." in a commit message - # (git-svn uses essentially the same procedure internally) - local svn_upstream=($(git log --first-parent -1 \ - --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null)) - if [[ 0 -ne ${#svn_upstream[@]} ]]; then - svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]} - svn_upstream=${svn_upstream%@*} - local n_stop="${#svn_remote[@]}" - for ((n=1; n <= n_stop; ++n)); do - svn_upstream=${svn_upstream#${svn_remote[$n]}} - done - - if [[ -z "$svn_upstream" ]]; then - # default branch name for checkouts with no layout: - upstream=${GIT_SVN_ID:-git-svn} - else - upstream=${svn_upstream#/} - fi - elif [[ "svn+git" = "$upstream" ]]; then - upstream="@{upstream}" - fi - ;; - esac - - # Find how many commits we are ahead/behind our upstream - if [[ -z "$legacy" ]]; then - count="$(git rev-list --count --left-right \ - "$upstream"...HEAD 2>/dev/null)" - else - # produce equivalent output to --count for older versions of git - local commits - if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)" - then - local commit behind=0 ahead=0 - for commit in $commits - do - case "$commit" in - "<"*) let ++behind - ;; - *) let ++ahead - ;; - esac - done - count="$behind $ahead" - else - count="" - fi - fi - - # calculate the result - if [[ -z "$verbose" ]]; then - case "$count" in - "") # no upstream - p="" ;; - "0 0") # equal to upstream - p="=" ;; - "0 "*) # ahead of upstream - p=">" ;; - *" 0") # behind upstream - p="<" ;; - *) # diverged from upstream - p="<>" ;; - esac - else - case "$count" in - "") # no upstream - p="" ;; - "0 0") # equal to upstream - p=" u=" ;; - "0 "*) # ahead of upstream - p=" u+${count#0 }" ;; - *" 0") # behind upstream - p=" u-${count% 0}" ;; - *) # diverged from upstream - p=" u+${count#* }-${count% *}" ;; - esac - 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/CHERRY_PICK_HEAD" ]; then - r="|CHERRY-PICKING" - 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 --tags --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="" - local p="" - - 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 - - if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then - __git_ps1_show_upstream - fi - fi - - local f="$w$i$s$u" - printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" - 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 -} - # The following function is based on code from: # # bash_completion - programmable completion functions for bash 3.2+ @@ -418,7 +151,6 @@ __git_reassemble_comp_words_by_ref() } if ! type _get_comp_words_by_ref >/dev/null 2>&1; then -if [[ -z ${ZSH_VERSION:+set} ]]; then _get_comp_words_by_ref () { local exclude cur_ words_ cword_ @@ -446,36 +178,20 @@ _get_comp_words_by_ref () shift done } -else -_get_comp_words_by_ref () +fi + +__gitcompadd () { - while [ $# -gt 0 ]; do - case "$1" in - cur) - cur=${COMP_WORDS[COMP_CWORD]} - ;; - prev) - prev=${COMP_WORDS[COMP_CWORD-1]} - ;; - words) - words=("${COMP_WORDS[@]}") - ;; - cword) - cword=$COMP_CWORD - ;; - -n) - # assume COMP_WORDBREAKS is already set sanely - shift - ;; - esac - shift + local i=0 + for x in $1; do + if [[ "$x" == "$3"* ]]; then + COMPREPLY[i++]="$2$x$4" + fi done } -fi -fi -# Generates completion reply with compgen, appending a space to possible -# completion words, if necessary. +# Generates completion reply, appending a space to possible completion words, +# if necessary. # It accepts 1 to 4 arguments: # 1: List of possible completion words. # 2: A prefix to be added to each possible completion word (optional). @@ -487,19 +203,25 @@ __gitcomp () case "$cur_" in --*=) - COMPREPLY=() ;; *) - local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" \ - -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur_")) + local c i=0 IFS=$' \t\n' + for c in $1; do + c="$c${4-}" + if [[ $c == "$cur_"* ]]; then + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + COMPREPLY[i++]="${2-}$c" + fi + done ;; esac } -# Generates completion reply with compgen from newline-separated possible -# completion words by appending a space to all of them. +# Generates completion reply from newline-separated possible completion words +# by appending a space to all of them. # It accepts 1 to 4 arguments: # 1: List of possible completion words, separated by a single newline. # 2: A prefix to be added to each possible completion word (optional). @@ -510,7 +232,69 @@ __gitcomp () __gitcomp_nl () { local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}")) + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" +} + +# Generates completion reply with compgen from newline-separated possible +# completion filenames. +# It accepts 1 to 3 arguments: +# 1: List of possible completion filenames, separated by a single newline. +# 2: A directory prefix to be added to each possible completion filename +# (optional). +# 3: Generate possible completion matches for this word (optional). +__gitcomp_file () +{ + local IFS=$'\n' + + # XXX does not work when the directory prefix contains a tilde, + # since tilde expansion is not applied. + # This means that COMPREPLY will be empty and Bash default + # completion will be used. + __gitcompadd "$1" "${2-}" "${3-$cur}" "" + + # use a hack to enable file mode in bash < 4 + compopt -o filenames +o nospace 2>/dev/null || + compgen -f /non-existing-dir/ > /dev/null +} + +# Execute 'git ls-files', unless the --committable option is specified, in +# which case it runs 'git diff-index' to find out the files that can be +# committed. It return paths relative to the directory specified in the first +# 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 +} + + +# __git_index_files accepts 1 or 2 arguments: +# 1: Options to pass to ls-files (required). +# 2: A directory path (optional). +# If provided, only files within the specified directory are listed. +# Sub directories are never recursed. Path must have a trailing +# slash. +__git_index_files () +{ + local dir="$(__gitdir)" root="${2-.}" file + + if [ -d "$dir" ]; then + __git_ls_files_helper "$root" "$1" | + while read -r file; do + case "$file" in + ?*/*) echo "${file%%/*}" ;; + *) echo "$file" ;; + esac + done | sort | uniq + fi } __git_heads () @@ -570,7 +354,7 @@ __git_refs () if [[ "$ref" == "$cur"* ]]; then echo "$ref" fi - done | uniq -u + done | sort | uniq -u fi return fi @@ -585,14 +369,8 @@ __git_refs () done ;; *) - git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \ - while read -r hash i; do - case "$i" in - *^{}) ;; - refs/*) echo "${i#refs/*/}" ;; - *) echo "$i" ;; - esac - done + echo "HEAD" + git for-each-ref --format="%(refname:short)" -- "refs/remotes/$dir/" | sed -e "s#^$dir/##" ;; esac } @@ -677,9 +455,7 @@ __git_complete_revlist_file () *) pfx="$ref:$pfx" ;; esac - local IFS=$'\n' - COMPREPLY=($(compgen -P "$pfx" \ - -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \ + __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" 2>/dev/null \ | sed '/^100... blob /{ s,^.* ,, s,$, , @@ -693,7 +469,7 @@ __git_complete_revlist_file () s,$,/, } s/^.* //')" \ - -- "$cur_")) + "$pfx" "$cur_" "" ;; *...*) pfx="${cur_%...*}..." @@ -712,6 +488,25 @@ __git_complete_revlist_file () } +# __git_complete_index_file requires 1 argument: +# 1: the options to pass to ls-file +# +# The exception is --committable, which finds the files appropriate commit. +__git_complete_index_file () +{ + local pfx="" cur_="$cur" + + case "$cur_" in + ?*/*) + pfx="${cur_%/*}" + cur_="${cur_##*/}" + pfx="${pfx}/" + ;; + esac + + __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_" +} + __git_complete_file () { __git_complete_revlist_file @@ -726,6 +521,9 @@ __git_complete_remote_or_refspec () { local cur_="$cur" cmd="${words[1]}" local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 + if [ "$cmd" = "remote" ]; then + ((c++)) + fi while [ $c -lt $cword ]; do i="${words[c]}" case "$i" in @@ -734,7 +532,6 @@ __git_complete_remote_or_refspec () case "$cmd" in push) no_complete_refspec=1 ;; fetch) - COMPREPLY=() return ;; *) ;; @@ -743,14 +540,13 @@ __git_complete_remote_or_refspec () -*) ;; *) remote="$i"; break ;; esac - c=$((++c)) + ((c++)) done if [ -z "$remote" ]; then __gitcomp_nl "$(__git_remotes)" return fi if [ $no_complete_refspec = 1 ]; then - COMPREPLY=() return fi [ "$remote" = "." ] && remote= @@ -776,7 +572,7 @@ __git_complete_remote_or_refspec () __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" fi ;; - pull) + pull|remote) if [ $lhs = 1 ]; then __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" else @@ -810,10 +606,19 @@ __git_complete_strategy () return 1 } +__git_commands () { + if test -n "${GIT_TESTING_COMMAND_COMPLETION:-}" + then + printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}" + else + git help -a|egrep '^ [a-zA-Z0-9]' + fi +} + __git_list_all_commands () { local i IFS=" "$'\n' - for i in $(git help -a|egrep '^ [a-zA-Z0-9]') + for i in $(__git_commands) do case $i in *--*) : helper pattern;; @@ -833,7 +638,7 @@ __git_list_porcelain_commands () { local i IFS=" "$'\n' __git_compute_all_commands - for i in "help" $__git_all_commands + for i in $__git_all_commands do case $i in *--*) : helper pattern;; @@ -842,10 +647,14 @@ __git_list_porcelain_commands () archimport) : import;; cat-file) : plumbing;; check-attr) : plumbing;; + check-ignore) : plumbing;; + check-mailmap) : plumbing;; check-ref-format) : plumbing;; checkout-index) : plumbing;; commit-tree) : plumbing;; count-objects) : infrequent;; + credential-cache) : credentials helper;; + credential-store) : credentials helper;; cvsexportcommit) : export;; cvsimport) : import;; cvsserver) : daemon;; @@ -983,7 +792,7 @@ __git_find_on_cmdline () return fi done - c=$((++c)) + ((c++)) done } @@ -994,11 +803,48 @@ __git_has_doubledash () if [ "--" = "${words[c]}" ]; then return 0 fi - c=$((++c)) + ((c++)) done return 1 } +# Try to count non option arguments passed on the command line for the +# specified git command. +# When options are used, it is necessary to use the special -- option to +# tell the implementation were non option arguments begin. +# XXX this can not be improved, since options can appear everywhere, as +# an example: +# git mv x -n y +# +# __git_count_arguments requires 1 argument: the git command executed. +__git_count_arguments () +{ + local word i c=0 + + # Skip "git" (first argument) + for ((i=1; i < ${#words[@]}; i++)); do + word="${words[i]}" + + case "$word" in + --) + # Good; we can assume that the following are only non + # option arguments. + ((c = 0)) + ;; + "$1") + # Skip the specified git command and discard git + # main options + ((c = 0)) + ;; + ?*) + ((c++)) + ;; + esac + done + + printf "%d" $c +} + __git_whitespacelist="nowarn warn error error-all fix" _git_am () @@ -1022,7 +868,6 @@ _git_am () " return esac - COMPREPLY=() } _git_apply () @@ -1042,13 +887,10 @@ _git_apply () " return esac - COMPREPLY=() } _git_add () { - __git_has_doubledash && return - case "$cur" in --*) __gitcomp " @@ -1057,7 +899,9 @@ _git_add () " return esac - COMPREPLY=() + + # XXX should we check for --update and --all options ? + __git_complete_index_file "--others --modified --directory --no-empty-directory" } _git_archive () @@ -1102,7 +946,6 @@ _git_bisect () __gitcomp_nl "$(__git_refs)" ;; *) - COMPREPLY=() ;; esac } @@ -1117,15 +960,19 @@ _git_branch () -d|-m) only_local_ref="y" ;; -r) has_r="y" ;; esac - c=$((++c)) + ((c++)) done case "$cur" in + --set-upstream-to=*) + __gitcomp "$(__git_refs)" "" "${cur##--set-upstream-to=}" + ;; --*) __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev --track --no-track --contains --merged --no-merged - --set-upstream --edit-description --list + --set-upstream-to= --edit-description --list + --unset-upstream " ;; *) @@ -1191,9 +1038,14 @@ _git_cherry () _git_cherry_pick () { + local dir="$(__gitdir)" + if [ -f "$dir"/CHERRY_PICK_HEAD ]; then + __gitcomp "--continue --quit --abort" + return + fi case "$cur" in --*) - __gitcomp "--edit --no-commit" + __gitcomp "--edit --no-commit --signoff --strategy= --mainline" ;; *) __gitcomp_nl "$(__git_refs)" @@ -1203,15 +1055,15 @@ _git_cherry_pick () _git_clean () { - __git_has_doubledash && return - case "$cur" in --*) __gitcomp "--dry-run --quiet" return ;; esac - COMPREPLY=() + + # XXX should we check for -x option ? + __git_complete_index_file "--others --directory" } _git_clone () @@ -1231,16 +1083,22 @@ _git_clone () --upload-pack --template= --depth + --single-branch + --branch " return ;; esac - COMPREPLY=() } _git_commit () { - __git_has_doubledash && return + case "$prev" in + -c|-C) + __gitcomp_nl "$(__git_refs)" "" "${cur}" + return + ;; + esac case "$cur" in --cleanup=*) @@ -1260,7 +1118,8 @@ _git_commit () --*) __gitcomp " --all --author= --signoff --verify --no-verify - --edit --amend --include --only --interactive + --edit --no-edit + --amend --include --only --interactive --dry-run --reuse-message= --reedit-message= --reset-author --file= --message= --template= --cleanup= --untracked-files --untracked-files= @@ -1268,7 +1127,13 @@ _git_commit () " return esac - COMPREPLY=() + + if git rev-parse --verify --quiet HEAD >/dev/null; then + __git_complete_index_file "--committable" + else + # This is the first commit + __git_complete_index_file "--cached" + fi } _git_describe () @@ -1284,6 +1149,8 @@ _git_describe () __gitcomp_nl "$(__git_refs)" } +__git_diff_algorithms="myers minimal patience histogram" + __git_diff_common_options="--stat --numstat --shortstat --summary --patch-with-stat --name-only --name-status --color --no-color --color-words --no-renames --check @@ -1294,10 +1161,11 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --no-ext-diff --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= - --patience - --raw + --patience --histogram --minimal + --raw --word-diff --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative + --diff-algorithm= " _git_diff () @@ -1305,6 +1173,10 @@ _git_diff () __git_has_doubledash && return case "$cur" in + --diff-algorithm=*) + __gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}" + return + ;; --*) __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex --base --ours --theirs --no-index @@ -1316,8 +1188,8 @@ _git_diff () __git_complete_revlist_file } -__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 +__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare " _git_difftool () @@ -1338,7 +1210,7 @@ _git_difftool () return ;; esac - __git_complete_file + __git_complete_revlist_file } __git_fetch_options=" @@ -1357,6 +1229,15 @@ _git_fetch () __git_complete_remote_or_refspec } +__git_format_patch_options=" + --stdout --attach --no-attach --thread --thread= --no-thread + --numbered --start-number --numbered-files --keep-subject --signoff + --signature --no-signature --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= + --output-directory --reroll-count --to= --quiet --notes +" + _git_format_patch () { case "$cur" in @@ -1367,21 +1248,7 @@ _git_format_patch () return ;; --*) - __gitcomp " - --stdout --attach --no-attach --thread --thread= - --output-directory - --numbered --start-number - --numbered-files - --keep-subject - --signoff --signature --no-signature - --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= - " + __gitcomp "$__git_format_patch_options" return ;; esac @@ -1399,7 +1266,6 @@ _git_fsck () return ;; esac - COMPREPLY=() } _git_gc () @@ -1410,7 +1276,6 @@ _git_gc () return ;; esac - COMPREPLY=() } _git_gitk () @@ -1487,13 +1352,10 @@ _git_init () return ;; esac - COMPREPLY=() } _git_ls_files () { - __git_has_doubledash && return - case "$cur" in --*) __gitcomp "--cached --deleted --modified --others --ignored @@ -1506,7 +1368,10 @@ _git_ls_files () return ;; esac - COMPREPLY=() + + # XXX ignore options like --modified and always suggest all cached + # files. + __git_complete_index_file "--cached" } _git_ls_remote () @@ -1622,7 +1487,6 @@ _git_mergetool () return ;; esac - COMPREPLY=() } _git_merge_base () @@ -1638,7 +1502,14 @@ _git_mv () return ;; esac - COMPREPLY=() + + if [ $(__git_count_arguments "mv") -gt 0 ]; then + # We need to show both cached and untracked files (including + # empty directories) since this may not be the last argument. + __git_complete_index_file "--cached --others --directory" + else + __git_complete_index_file "--cached" + fi } _git_name_rev () @@ -1656,7 +1527,7 @@ _git_notes () __gitcomp '--ref' ;; ,*) - case "${words[cword-1]}" in + case "$prev" in --ref) __gitcomp_nl "$(__git_refs)" ;; @@ -1682,7 +1553,7 @@ _git_notes () prune,*) ;; *) - case "${words[cword-1]}" in + case "$prev" in -m|-F) ;; *) @@ -1795,6 +1666,12 @@ _git_send_email () __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" return ;; + --thread=*) + __gitcomp " + deep shallow + " "" "${cur##--thread=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to --compose --confirm= --dry-run --envelope-sender @@ -1804,11 +1681,12 @@ _git_send_email () --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" + --validate --no-validate + $__git_format_patch_options" return ;; esac - COMPREPLY=() + __git_complete_revlist } _git_stage () @@ -1822,7 +1700,7 @@ __git_config_get_set_variables () while [ $c -gt 1 ]; do word="${words[c]}" case "$word" in - --global|--system|--file=*) + --system|--global|--local|--file=*) config_file="$word" break ;; @@ -1849,7 +1727,7 @@ __git_config_get_set_variables () _git_config () { case "$prev" in - branch.*.remote) + branch.*.remote|branch.*.pushremote) __gitcomp_nl "$(__git_remotes)" return ;; @@ -1857,11 +1735,19 @@ _git_config () __gitcomp_nl "$(__git_refs)" return ;; + branch.*.rebase) + __gitcomp "false true" + return + ;; + remote.pushdefault) + __gitcomp_nl "$(__git_remotes)" + return + ;; remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then - COMPREPLY=("refs/heads/") + __gitcomp_nl "refs/heads/" "" "" "" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" @@ -1896,6 +1782,10 @@ _git_config () " return ;; + diff.submodule) + __gitcomp "log short" + return + ;; help.format) __gitcomp "man info web html" return @@ -1921,14 +1811,13 @@ _git_config () return ;; *.*) - COMPREPLY=() return ;; esac case "$cur" in --*) __gitcomp " - --global --system --file= + --system --global --local --file= --list --replace-all --get --get-all --get-regexp --add --unset --unset-all @@ -1938,7 +1827,7 @@ _git_config () ;; branch.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" - __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur_" + __gitcomp "remote pushremote merge mergeoptions rebase" "$pfx" "$cur_" return ;; branch.*) @@ -2069,7 +1958,6 @@ _git_config () core.fileMode core.fsyncobjectfiles core.gitProxy - core.ignoreCygwinFSTricks core.ignoreStat core.ignorecase core.logAllRefUpdates @@ -2097,9 +1985,12 @@ _git_config () diff.noprefix diff.renameLimit diff.renames + diff.statGraphWidth + diff.submodule diff.suppressBlankEmpty diff.tool diff.wordRegex + diff.algorithm difftool. difftool.prompt fetch.recurseSubmodules @@ -2230,6 +2121,7 @@ _git_config () receive.fsckObjects receive.unpackLimit receive.updateserverinfo + remote.pushdefault remotes. repack.usedeltabaseoffset rerere.autoupdate @@ -2277,7 +2169,7 @@ _git_config () _git_remote () { - local subcommands="add rename rm show prune update set-head" + local subcommands="add rename remove set-head set-branches set-url show prune update" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" @@ -2285,9 +2177,12 @@ _git_remote () fi case "$subcommand" in - rename|rm|show|prune) + rename|remove|set-url|show|prune) __gitcomp_nl "$(__git_remotes)" ;; + set-head|set-branches) + __git_complete_remote_or_refspec + ;; update) local i c='' IFS=$'\n' for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do @@ -2297,7 +2192,6 @@ _git_remote () __gitcomp "$c" ;; *) - COMPREPLY=() ;; esac } @@ -2333,15 +2227,14 @@ _git_revert () _git_rm () { - __git_has_doubledash && return - case "$cur" in --*) __gitcomp "--cached --dry-run --ignore-unmatch --quiet" return ;; esac - COMPREPLY=() + + __git_complete_index_file "--cached" } _git_shortlog () @@ -2371,6 +2264,10 @@ _git_show () " "" "${cur#*=}" return ;; + --diff-algorithm=*) + __gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}" + return + ;; --*) __gitcomp "--pretty= --format= --abbrev-commit --oneline $__git_diff_common_options @@ -2378,7 +2275,7 @@ _git_show () return ;; esac - __git_complete_file + __git_complete_revlist_file } _git_show_branch () @@ -2410,8 +2307,6 @@ _git_stash () *) if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then __gitcomp "$subcommands" - else - COMPREPLY=() fi ;; esac @@ -2424,14 +2319,12 @@ _git_stash () __gitcomp "--index --quiet" ;; show,--*|drop,--*|branch,--*) - COMPREPLY=() ;; show,*|apply,*|drop,*|pop,*|branch,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; *) - COMPREPLY=() ;; esac fi @@ -2441,7 +2334,7 @@ _git_submodule () { __git_has_doubledash && return - local subcommands="add status init update summary foreach sync" + local subcommands="add status init deinit update summary foreach sync" if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then case "$cur" in --*) @@ -2473,7 +2366,7 @@ _git_svn () --no-metadata --use-svm-props --use-svnsync-props --log-window-size= --no-checkout --quiet --repack-flags --use-log-author --localtime - --ignore-paths= $remote_opts + --ignore-paths= --include-paths= $remote_opts " local init_opts=" --template= --shared= --trunk= --tags= @@ -2500,7 +2393,7 @@ _git_svn () __gitcomp " --merge --strategy= --verbose --dry-run --fetch-all --no-rebase --commit-url - --revision $cmt_opts $fc_opts + --revision --interactive $cmt_opts $fc_opts " ;; set-tree,--*) @@ -2548,7 +2441,6 @@ _git_svn () __gitcomp "--revision= --parent" ;; *) - COMPREPLY=() ;; esac fi @@ -2568,18 +2460,15 @@ _git_tag () f=1 ;; esac - c=$((++c)) + ((c++)) done case "$prev" in -m|-F) - COMPREPLY=() ;; -*|tag) if [ $f = 1 ]; then __gitcomp_nl "$(__git_tags)" - else - COMPREPLY=() fi ;; *) @@ -2593,35 +2482,22 @@ _git_whatchanged () _git_log } -_git () +__git_main () { local i c=1 command __git_dir - if [[ -n ${ZSH_VERSION-} ]]; then - emulate -L bash - setopt KSH_TYPESET - - # workaround zsh's bug that leaves 'words' as a special - # variable in versions < 4.3.12 - typeset -h words - - # workaround zsh's bug that quotes spaces in the COMPREPLY - # array if IFS doesn't contain spaces. - typeset -h IFS - fi - - local cur words cword prev - _get_comp_words_by_ref -n =: cur words cword prev while [ $c -lt $cword ]; do i="${words[c]}" case "$i" in --git-dir=*) __git_dir="${i#--git-dir=}" ;; + --git-dir) ((c++)) ; __git_dir="${words[c]}" ;; --bare) __git_dir="." ;; - --version|-p|--paginate) ;; --help) command="help"; break ;; + -c|--work-tree|--namespace) ((c++)) ;; + -*) ;; *) command="$i"; break ;; esac - c=$((++c)) + ((c++)) done if [ -z "$command" ]; then @@ -2633,9 +2509,13 @@ _git () --bare --version --exec-path + --exec-path= --html-path + --man-path + --info-path --work-tree= --namespace= + --no-replace-objects --help " ;; @@ -2655,24 +2535,8 @@ _git () fi } -_gitk () +__gitk_main () { - if [[ -n ${ZSH_VERSION-} ]]; then - emulate -L bash - setopt KSH_TYPESET - - # workaround zsh's bug that leaves 'words' as a special - # variable in versions < 4.3.12 - typeset -h words - - # workaround zsh's bug that quotes spaces in the COMPREPLY - # array if IFS doesn't contain spaces. - typeset -h IFS - fi - - local cur words cword prev - _get_comp_words_by_ref -n =: cur words cword prev - __git_has_doubledash && return local g="$(__gitdir)" @@ -2693,16 +2557,107 @@ _gitk () __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 +if [[ -n ${ZSH_VERSION-} ]]; then + echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2 + + autoload -U +X compinit && compinit + + __gitcomp () + { + emulate -L zsh + + local cur_="${3-$cur}" + + case "$cur_" in + --*=) + ;; + *) + local c IFS=$' \t\n' + local -a array + for c in ${=1}; do + c="$c${4-}" + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + array[${#array[@]}+1]="$c" + done + compset -P '*[=:]' + compadd -Q -S '' -p "${2-}" -a -- array && _ret=0 + ;; + esac + } + + __gitcomp_nl () + { + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 + } + + __gitcomp_file () + { + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -p "${2-}" -f -- ${=1} && _ret=0 + } + + _git () + { + local _ret=1 cur cword prev + cur=${words[CURRENT]} + prev=${words[CURRENT-1]} + let cword=CURRENT-1 + emulate ksh -c __${service}_main + let _ret && _default && _ret=0 + return _ret + } + + compdef _git git gitk + return +fi + +__git_func_wrap () +{ + local cur words cword prev + _get_comp_words_by_ref -n =: cur words cword prev + $1 +} + +# Setup completion for certain functions defined above by setting common +# variables and workarounds. +# This is NOT a public function; use at your own risk. +__git_complete () +{ + local wrapper="__git_wrap${2}" + eval "$wrapper () { __git_func_wrap $2 ; }" + complete -o bashdefault -o default -o nospace -F $wrapper $1 2>/dev/null \ + || complete -o default -o nospace -F $wrapper $1 +} + +# wrapper for backwards compatibility +_git () +{ + __git_wrap__git_main +} + +# wrapper for backwards compatibility +_gitk () +{ + __git_wrap__gitk_main +} + +__git_complete git __git_main +__git_complete gitk __gitk_main # 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 +__git_complete git.exe __git_main fi |