diff options
Diffstat (limited to 'contrib/completion/git-completion.bash')
-rwxr-xr-x | contrib/completion/git-completion.bash | 976 |
1 files changed, 718 insertions, 258 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 9651720410..98af8f5c7e 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1,6 +1,6 @@ #!bash # -# bash completion support for core Git. +# bash/zsh completion support for core Git. # # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). @@ -18,11 +18,12 @@ # To use these routines: # # 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). -# 2) Added the following line to your .bashrc: +# 2) Add the following line to your .bashrc/.zshrc: # source ~/.git-completion.sh # # 3) Consider changing your PS1 to also show the current branch: -# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' +# 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 @@ -42,6 +43,24 @@ # 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. +# +# # To submit patches: # # *) Read Documentation/SubmittingPatches @@ -54,6 +73,10 @@ # git@vger.kernel.org # +if [[ -n ${ZSH_VERSION-} ]]; then + autoload -U +X bashcompinit && bashcompinit +fi + case "$COMP_WORDBREAKS" in *:*) : great ;; *) COMP_WORDBREAKS="$COMP_WORDBREAKS:" @@ -78,14 +101,135 @@ __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 + output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')" + while read 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 + local r="" + local b="" if [ -f "$g/rebase-merge/interactive" ]; then r="|REBASE-i" b="$(cat "$g/rebase-merge/head-name")" @@ -103,6 +247,8 @@ __git_ps1 () 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 @@ -118,7 +264,7 @@ __git_ps1 () (describe) git describe HEAD ;; (* | default) - git describe --exact-match HEAD ;; + git describe --tags --exact-match HEAD ;; esac 2>/dev/null)" || b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || @@ -127,11 +273,12 @@ __git_ps1 () } fi - local w - local i - local s - local u - local c + 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 @@ -159,10 +306,14 @@ __git_ps1 () 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" + printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" fi } @@ -179,15 +330,172 @@ __gitcomp_1 () done } +# The following function is based on code from: +# +# bash_completion - programmable completion functions for bash 3.2+ +# +# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org> +# © 2009-2010, Bash Completion Maintainers +# <bash-completion-devel@lists.alioth.debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The latest version of this software can be obtained here: +# +# http://bash-completion.alioth.debian.org/ +# +# RELEASE: 2.x + +# This function can be used to access a tokenized list of words +# on the command line: +# +# __git_reassemble_comp_words_by_ref '=:' +# if test "${words_[cword_-1]}" = -w +# then +# ... +# fi +# +# The argument should be a collection of characters from the list of +# word completion separators (COMP_WORDBREAKS) to treat as ordinary +# characters. +# +# This is roughly equivalent to going back in time and setting +# COMP_WORDBREAKS to exclude those characters. The intent is to +# make option types like --date=<type> and <rev>:<path> easy to +# recognize by treating each shell word as a single token. +# +# It is best not to set COMP_WORDBREAKS directly because the value is +# shared with other completion scripts. By the time the completion +# function gets called, COMP_WORDS has already been populated so local +# changes to COMP_WORDBREAKS have no effect. +# +# Output: words_, cword_, cur_. + +__git_reassemble_comp_words_by_ref() +{ + local exclude i j first + # Which word separators to exclude? + exclude="${1//[^$COMP_WORDBREAKS]}" + cword_=$COMP_CWORD + if [ -z "$exclude" ]; then + words_=("${COMP_WORDS[@]}") + return + fi + # List of word completion separators has shrunk; + # re-assemble words to complete. + for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do + # Append each nonempty word consisting of just + # word separator characters to the current word. + first=t + while + [ $i -gt 0 ] && + [ -n "${COMP_WORDS[$i]}" ] && + # word consists of excluded word separators + [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ] + do + # Attach to the previous token, + # unless the previous token is the command name. + if [ $j -ge 2 ] && [ -n "$first" ]; then + ((j--)) + fi + first= + words_[$j]=${words_[j]}${COMP_WORDS[i]} + if [ $i = $COMP_CWORD ]; then + cword_=$j + fi + if (($i < ${#COMP_WORDS[@]} - 1)); then + ((i++)) + else + # Done. + return + fi + done + words_[$j]=${words_[j]}${COMP_WORDS[i]} + if [ $i = $COMP_CWORD ]; then + cword_=$j + fi + done +} + +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_ + if [ "$1" = "-n" ]; then + exclude=$2 + shift 2 + fi + __git_reassemble_comp_words_by_ref "$exclude" + cur_=${words_[cword_]} + while [ $# -gt 0 ]; do + case "$1" in + cur) + cur=$cur_ + ;; + prev) + prev=${words_[$cword_-1]} + ;; + words) + words=("${words_[@]}") + ;; + cword) + cword=$cword_ + ;; + esac + shift + done +} +else +_get_comp_words_by_ref () +{ + 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 + done +} +fi +fi + # __gitcomp accepts 1, 2, 3, or 4 arguments # generates completion reply with compgen __gitcomp () { - local cur="${COMP_WORDS[COMP_CWORD]}" + local cur_="$cur" + if [ $# -gt 2 ]; then - cur="$3" + cur_="$3" fi - case "$cur" in + case "$cur_" in --*=) COMPREPLY=() ;; @@ -195,7 +503,7 @@ __gitcomp () local IFS=$'\n' COMPREPLY=($(compgen -P "${2-}" \ -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur")) + -- "$cur_")) ;; esac } @@ -238,25 +546,45 @@ __git_tags () done } -# __git_refs accepts 0 or 1 arguments (to pass to __gitdir) +# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments +# presence of 2nd argument means use the guess heuristic employed +# by checkout for tracking branches __git_refs () { - local i is_hash=y dir="$(__gitdir "${1-}")" - local cur="${COMP_WORDS[COMP_CWORD]}" format refs + local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}" + local format refs if [ -d "$dir" ]; then case "$cur" in refs|refs/*) format="refname" refs="${cur%/*}" + track="" ;; *) - if [ -e "$dir/HEAD" ]; then echo HEAD; fi + 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 + if [ -n "$track" ]; then + # employ the heuristic used by git checkout + # Try to find a remote branch that matches the completion word + # but only output if the branch name is unique + local ref entry + git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \ + "refs/remotes/" | \ + while read entry; do + eval "$entry" + ref="${ref#*/}" + if [[ "$ref" == "$cur"* ]]; then + echo "$ref" + fi + done | uniq -u + fi return fi for i in $(git ls-remote "$dir" 2>/dev/null); do @@ -301,12 +629,12 @@ __git_refs_remotes () __git_remotes () { local i ngoff IFS=$'\n' d="$(__gitdir)" - shopt -q nullglob || ngoff=1 - shopt -s nullglob + __git_shopt -q nullglob || ngoff=1 + __git_shopt -s nullglob for i in "$d/remotes"/*; do echo ${i#$d/remotes/} done - [ "$ngoff" ] && shopt -u nullglob + [ "$ngoff" ] && __git_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*/}" @@ -336,24 +664,27 @@ __git_compute_merge_strategies () : ${__git_merge_strategies:=$(__git_list_merge_strategies)} } -__git_complete_file () +__git_complete_revlist_file () { - local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in + local pfx ls ref cur_="$cur" + case "$cur_" in + *..?*:*) + return + ;; ?*:*) - ref="${cur%%:*}" - cur="${cur#*:}" - case "$cur" in + ref="${cur_%%:*}" + cur_="${cur_#*:}" + case "$cur_" in ?*/*) - pfx="${cur%/*}" - cur="${cur##*/}" + pfx="${cur_%/*}" + cur_="${cur_##*/}" ls="$ref:$pfx" pfx="$pfx/" ;; *) ls="$ref" ;; - esac + esac case "$COMP_WORDBREAKS" in *:*) : great ;; @@ -376,27 +707,17 @@ __git_complete_file () s,$,/, } s/^.* //')" \ - -- "$cur")) + -- "$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_" ;; *..*) - pfx="${cur%..*}.." - cur="${cur#*..}" - __gitcomp "$(__git_refs)" "$pfx" "$cur" + pfx="${cur_%..*}.." + cur_="${cur_#*..}" + __gitcomp "$(__git_refs)" "$pfx" "$cur_" ;; *) __gitcomp "$(__git_refs)" @@ -404,13 +725,23 @@ __git_complete_revlist () esac } + +__git_complete_file () +{ + __git_complete_revlist_file +} + +__git_complete_revlist () +{ + __git_complete_revlist_file +} + __git_complete_remote_or_refspec () { - local cmd="${COMP_WORDS[1]}" - local cur="${COMP_WORDS[COMP_CWORD]}" + local cur_="$cur" cmd="${words[1]}" local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" + while [ $c -lt $cword ]; do + i="${words[c]}" case "$i" in --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; --all) @@ -437,40 +768,40 @@ __git_complete_remote_or_refspec () return fi [ "$remote" = "." ] && remote= - case "$cur" in + case "$cur_" in *:*) case "$COMP_WORDBREAKS" in *:*) : great ;; - *) pfx="${cur%%:*}:" ;; + *) pfx="${cur_%%:*}:" ;; esac - cur="${cur#*:}" + cur_="${cur_#*:}" lhs=0 ;; +*) pfx="+" - cur="${cur#+}" + cur_="${cur_#+}" ;; esac case "$cmd" in fetch) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur" + __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur_" else - __gitcomp "$(__git_refs)" "$pfx" "$cur" + __gitcomp "$(__git_refs)" "$pfx" "$cur_" fi ;; pull) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" + __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_" else - __gitcomp "$(__git_refs)" "$pfx" "$cur" + __gitcomp "$(__git_refs)" "$pfx" "$cur_" fi ;; push) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs)" "$pfx" "$cur" + __gitcomp "$(__git_refs)" "$pfx" "$cur_" else - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" + __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_" fi ;; esac @@ -479,12 +810,11 @@ __git_complete_remote_or_refspec () __git_complete_strategy () { __git_compute_merge_strategies - case "${COMP_WORDS[COMP_CWORD-1]}" in + case "$prev" 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=}" @@ -567,7 +897,7 @@ __git_list_porcelain_commands () quiltimport) : import;; read-tree) : plumbing;; receive-pack) : plumbing;; - reflog) : plumbing;; + remote-*) : transport;; repo-config) : deprecated;; rerere) : plumbing;; rev-list) : plumbing;; @@ -605,6 +935,19 @@ __git_compute_porcelain_commands () : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)} } +__git_pretty_aliases () +{ + local i IFS=$'\n' + for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do + case "$i" in + pretty.*) + i="${i#pretty.}" + echo "${i/ */}" + ;; + esac + done +} + __git_aliases () { local i IFS=$'\n' @@ -624,10 +967,19 @@ __git_aliased_command () local word cmdline=$(git --git-dir="$(__gitdir)" \ config --get "alias.$1") for word in $cmdline; do - if [ "${word##-*}" ]; then - echo $word + case "$word" in + \!gitk|gitk) + echo "gitk" return - fi + ;; + \!*) : shell command alias ;; + -*) : option ;; + *=*) : setting env ;; + git) : git itself ;; + *) + echo "$word" + return + esac done } @@ -635,9 +987,8 @@ __git_aliased_command () __git_find_on_cmdline () { local word subcommand c=1 - - while [ $c -lt $COMP_CWORD ]; do - word="${COMP_WORDS[c]}" + while [ $c -lt $cword ]; do + word="${words[c]}" for subcommand in $1; do if [ "$subcommand" = "$word" ]; then echo "$subcommand" @@ -651,8 +1002,8 @@ __git_find_on_cmdline () __git_has_doubledash () { local c=1 - while [ $c -lt $COMP_CWORD ]; do - if [ "--" = "${COMP_WORDS[c]}" ]; then + while [ $c -lt $cword ]; do + if [ "--" = "${words[c]}" ]; then return 0 fi c=$((++c)) @@ -664,9 +1015,9 @@ __git_whitespacelist="nowarn warn error error-all fix" _git_am () { - local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" + local dir="$(__gitdir)" if [ -d "$dir"/rebase-apply ]; then - __gitcomp "--skip --resolved --abort" + __gitcomp "--skip --continue --resolved --abort" return fi case "$cur" in @@ -688,7 +1039,6 @@ _git_am () _git_apply () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --whitespace=*) __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" @@ -711,7 +1061,6 @@ _git_add () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -725,7 +1074,6 @@ _git_add () _git_archive () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --format=*) __gitcomp "$(git archive --list)" "" "${cur##--format=}" @@ -753,12 +1101,16 @@ _git_bisect () local subcommands="start bad good skip reset visualize replay log run" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then - __gitcomp "$subcommands" + if [ -f "$(__gitdir)"/BISECT_START ]; then + __gitcomp "$subcommands" + else + __gitcomp "replay start" + fi return fi case "$subcommand" in - bad|good|reset|skip) + bad|good|reset|skip|start) __gitcomp "$(__git_refs)" ;; *) @@ -771,8 +1123,8 @@ _git_branch () { local i c=1 only_local_ref="n" has_r="n" - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" + while [ $c -lt $cword ]; do + i="${words[c]}" case "$i" in -d|-m) only_local_ref="y" ;; -r) has_r="y" ;; @@ -780,11 +1132,12 @@ _git_branch () c=$((++c)) done - case "${COMP_WORDS[COMP_CWORD]}" in + case "$cur" in --*) __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev --track --no-track --contains --merged --no-merged + --set-upstream " ;; *) @@ -799,8 +1152,8 @@ _git_branch () _git_bundle () { - local cmd="${COMP_WORDS[2]}" - case "$COMP_CWORD" in + local cmd="${words[2]}" + case "$cword" in 2) __gitcomp "create list-heads verify unbundle" ;; @@ -821,7 +1174,6 @@ _git_checkout () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --conflict=*) __gitcomp "diff3 merge" "" "${cur##--conflict=}" @@ -829,11 +1181,17 @@ _git_checkout () --*) __gitcomp " --quiet --ours --theirs --track --no-track --merge - --conflict= --patch + --conflict= --orphan --patch " ;; *) - __gitcomp "$(__git_refs)" + # check if --track, --no-track, or --no-guess was specified + # if so, disable DWIM mode + local flags="--track --no-track --no-guess" track=1 + if [ -n "$(__git_find_on_cmdline "$flags")" ]; then + track='' + fi + __gitcomp "$(__git_refs '' $track)" ;; esac } @@ -845,7 +1203,6 @@ _git_cherry () _git_cherry_pick () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--edit --no-commit" @@ -860,7 +1217,6 @@ _git_clean () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--dry-run --quiet" @@ -872,7 +1228,6 @@ _git_clean () _git_clone () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -899,19 +1254,15 @@ _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=}" + --reuse-message=*|--reedit-message=*|\ + --fixup=*|--squash=*) + __gitcomp "$(__git_refs)" "" "${cur#*=}" return ;; --untracked-files=*) @@ -925,7 +1276,7 @@ _git_commit () --dry-run --reuse-message= --reedit-message= --reset-author --file= --message= --template= --cleanup= --untracked-files --untracked-files= - --verbose --quiet + --verbose --quiet --fixup= --squash= " return esac @@ -934,7 +1285,6 @@ _git_commit () _git_describe () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -966,28 +1316,26 @@ _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 + --base --ours --theirs --no-index $__git_diff_common_options " return ;; esac - __git_complete_file + __git_complete_revlist_file } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 " _git_difftool () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}" @@ -1012,7 +1360,6 @@ __git_fetch_options=" _git_fetch () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "$__git_fetch_options" @@ -1024,7 +1371,6 @@ _git_fetch () _git_format_patch () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --thread=*) __gitcomp " @@ -1039,7 +1385,7 @@ _git_format_patch () --numbered --start-number --numbered-files --keep-subject - --signoff + --signoff --signature --no-signature --in-reply-to= --cc= --full-index --binary --not --all @@ -1056,7 +1402,6 @@ _git_format_patch () _git_fsck () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -1071,7 +1416,6 @@ _git_fsck () _git_gc () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--prune --aggressive" @@ -1081,18 +1425,27 @@ _git_gc () COMPREPLY=() } +_git_gitk () +{ + _gitk +} + +__git_match_ctag() { + awk "/^${1////\\/}/ { print \$1 }" "$2" +} + _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 + --full-name --line-number --extended-regexp --basic-regexp --fixed-strings + --perl-regexp --files-with-matches --name-only --files-without-match --max-depth @@ -1103,12 +1456,20 @@ _git_grep () ;; esac + case "$cword,$prev" in + 2,*|*,-*) + if test -r tags; then + __gitcomp "$(__git_match_ctag "$cur" tags)" + return + fi + ;; + esac + __gitcomp "$(__git_refs)" } _git_help () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--all --info --man --web" @@ -1116,17 +1477,16 @@ _git_help () ;; esac __git_compute_all_commands - __gitcomp "$__git_all_commands + __gitcomp "$__git_all_commands $(__git_aliases) attributes cli core-tutorial cvs-migration diffcore gitk glossary hooks ignore modules - repository-layout tutorial tutorial-2 + namespaces repository-layout tutorial tutorial-2 workflows " } _git_init () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --shared=*) __gitcomp " @@ -1146,7 +1506,6 @@ _git_ls_files () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--cached --deleted --modified --others --ignored @@ -1180,12 +1539,14 @@ __git_log_common_options=" --max-count= --max-age= --since= --after= --min-age= --until= --before= + --min-parents= --max-parents= + --no-min-parents --no-max-parents " # 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 + --left-right --notes --no-notes " # Options that go well for log and shortlog (not gitk) __git_log_shortlog_options=" @@ -1200,21 +1561,15 @@ _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=}" + --pretty=*|--format=*) + __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases) + " "" "${cur#*=}" return ;; --date=*) @@ -1259,7 +1614,6 @@ _git_merge () { __git_complete_strategy && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "$__git_merge_options" @@ -1270,7 +1624,6 @@ _git_merge () _git_mergetool () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" @@ -1291,7 +1644,6 @@ _git_merge_base () _git_mv () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--dry-run" @@ -1306,11 +1658,57 @@ _git_name_rev () __gitcomp "--tags --all --stdin" } +_git_notes () +{ + local subcommands='add append copy edit list prune remove show' + local subcommand="$(__git_find_on_cmdline "$subcommands")" + + case "$subcommand,$cur" in + ,--*) + __gitcomp '--ref' + ;; + ,*) + case "${words[cword-1]}" in + --ref) + __gitcomp "$(__git_refs)" + ;; + *) + __gitcomp "$subcommands --ref" + ;; + esac + ;; + add,--reuse-message=*|append,--reuse-message=*|\ + add,--reedit-message=*|append,--reedit-message=*) + __gitcomp "$(__git_refs)" "" "${cur#*=}" + ;; + add,--*|append,--*) + __gitcomp '--file= --message= --reedit-message= + --reuse-message=' + ;; + copy,--*) + __gitcomp '--stdin' + ;; + prune,--*) + __gitcomp '--dry-run --verbose' + ;; + prune,*) + ;; + *) + case "${words[cword-1]}" in + -m|-F) + ;; + *) + __gitcomp "$(__git_refs)" + ;; + esac + ;; + esac +} + _git_pull () { __git_complete_strategy && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -1326,8 +1724,7 @@ _git_pull () _git_push () { - local cur="${COMP_WORDS[COMP_CWORD]}" - case "${COMP_WORDS[COMP_CWORD-1]}" in + case "$prev" in --repo) __gitcomp "$(__git_remotes)" return @@ -1340,7 +1737,7 @@ _git_push () --*) __gitcomp " --all --mirror --tags --dry-run --force --verbose - --receive-pack= --repo= + --receive-pack= --repo= --set-upstream " return ;; @@ -1350,7 +1747,7 @@ _git_push () _git_rebase () { - local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" + local dir="$(__gitdir)" if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then __gitcomp "--continue --skip --abort" return @@ -1367,6 +1764,7 @@ _git_rebase () --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= + --autosquash " return @@ -1374,12 +1772,23 @@ _git_rebase () __gitcomp "$(__git_refs)" } +_git_reflog () +{ + local subcommands="show delete expire" + local subcommand="$(__git_find_on_cmdline "$subcommands")" + + if [ -z "$subcommand" ]; then + __gitcomp "$subcommands" + else + __gitcomp "$(__git_refs)" + fi +} + __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 " @@ -1414,11 +1823,16 @@ _git_send_email () COMPREPLY=() } +_git_stage () +{ + _git_add +} + __git_config_get_set_variables () { - local prevword word config_file= c=$COMP_CWORD + local prevword word config_file= c=$cword while [ $c -gt 1 ]; do - word="${COMP_WORDS[c]}" + word="${words[c]}" case "$word" in --global|--system|--file=*) config_file="$word" @@ -1446,9 +1860,7 @@ __git_config_get_set_variables () _git_config () { - local cur="${COMP_WORDS[COMP_CWORD]}" - local prv="${COMP_WORDS[COMP_CWORD-1]}" - case "$prv" in + case "$prev" in branch.*.remote) __gitcomp "$(__git_remotes)" return @@ -1458,13 +1870,13 @@ _git_config () return ;; remote.*.fetch) - local remote="${prv#remote.}" + local remote="${prev#remote.}" remote="${remote%.fetch}" __gitcomp "$(__git_refs_remotes "$remote")" return ;; remote.*.push) - local remote="${prv#remote.}" + local remote="${prev#remote.}" remote="${remote%.push}" __gitcomp "$(git --git-dir="$(__gitdir)" \ for-each-ref --format='%(refname):%(refname)' \ @@ -1533,98 +1945,108 @@ _git_config () return ;; branch.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur" + local pfx="${cur%.*}." cur_="${cur##*.}" + __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur_" return ;; branch.*) - local pfx="${cur%.*}." - cur="${cur#*.}" - __gitcomp "$(__git_heads)" "$pfx" "$cur" "." + local pfx="${cur%.*}." cur_="${cur#*.}" + __gitcomp "$(__git_heads)" "$pfx" "$cur_" "." return ;; guitool.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" + local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp " argprompt cmd confirm needsfile noconsole norescan prompt revprompt revunmerged title - " "$pfx" "$cur" + " "$pfx" "$cur_" return ;; difftool.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "cmd path" "$pfx" "$cur" + local pfx="${cur%.*}." cur_="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur_" return ;; man.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "cmd path" "$pfx" "$cur" + local pfx="${cur%.*}." cur_="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur_" return ;; mergetool.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "cmd path trustExitCode" "$pfx" "$cur" + local pfx="${cur%.*}." cur_="${cur##*.}" + __gitcomp "cmd path trustExitCode" "$pfx" "$cur_" return ;; pager.*) - local pfx="${cur%.*}." - cur="${cur#*.}" + local pfx="${cur%.*}." cur_="${cur#*.}" __git_compute_all_commands - __gitcomp "$__git_all_commands" "$pfx" "$cur" + __gitcomp "$__git_all_commands" "$pfx" "$cur_" return ;; remote.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" + local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp " url proxy fetch push mirror skipDefaultUpdate receivepack uploadpack tagopt pushurl - " "$pfx" "$cur" + " "$pfx" "$cur_" return ;; remote.*) - local pfx="${cur%.*}." - cur="${cur#*.}" - __gitcomp "$(__git_remotes)" "$pfx" "$cur" "." + local pfx="${cur%.*}." cur_="${cur#*.}" + __gitcomp "$(__git_remotes)" "$pfx" "$cur_" "." return ;; url.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur" + local pfx="${cur%.*}." cur_="${cur##*.}" + __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" return ;; esac __gitcomp " - add.ignore-errors + add.ignoreErrors + advice.commitBeforeMerge + advice.detachedHead + advice.implicitIdentity + advice.pushNonFastForward + advice.resolveConflict + advice.statusHints alias. + am.keepcr apply.ignorewhitespace apply.whitespace branch.autosetupmerge branch.autosetuprebase + browser. clean.requireForce color.branch color.branch.current color.branch.local color.branch.plain color.branch.remote + color.decorate.HEAD + color.decorate.branch + color.decorate.remoteBranch + color.decorate.stash + color.decorate.tag color.diff color.diff.commit color.diff.frag + color.diff.func color.diff.meta color.diff.new color.diff.old color.diff.plain color.diff.whitespace color.grep - color.grep.external + color.grep.context + color.grep.filename + color.grep.function + color.grep.linenumber color.grep.match + color.grep.selected + color.grep.separator color.interactive + color.interactive.error color.interactive.header color.interactive.help color.interactive.prompt @@ -1638,21 +2060,29 @@ _git_config () color.status.untracked color.status.updated color.ui + commit.status commit.template + core.abbrev + core.askpass + core.attributesfile core.autocrlf core.bare + core.bigFileThreshold core.compression core.createObject core.deltaBaseCacheLimit core.editor + core.eol core.excludesfile core.fileMode core.fsyncobjectfiles core.gitProxy core.ignoreCygwinFSTricks core.ignoreStat + core.ignorecase core.logAllRefUpdates core.loosecompression + core.notesRef core.packedGitLimit core.packedGitWindowSize core.pager @@ -1662,6 +2092,7 @@ _git_config () core.repositoryFormatVersion core.safecrlf core.sharedRepository + core.sparseCheckout core.symlinks core.trustctime core.warnAmbiguousRefs @@ -1669,25 +2100,30 @@ _git_config () core.worktree diff.autorefreshindex diff.external + diff.ignoreSubmodules diff.mnemonicprefix + diff.noprefix diff.renameLimit - diff.renameLimit. diff.renames diff.suppressBlankEmpty diff.tool diff.wordRegex difftool. difftool.prompt + fetch.recurseSubmodules fetch.unpackLimit format.attach format.cc format.headers format.numbered format.pretty + format.signature format.signoff format.subjectprefix format.suffix format.thread + format.to + gc. gc.aggressiveWindow gc.auto gc.autopacklimit @@ -1725,15 +2161,20 @@ _git_config () http.lowSpeedLimit http.lowSpeedTime http.maxRequests + http.minSessions http.noEPSV + http.postBuffer http.proxy http.sslCAInfo http.sslCAPath http.sslCert + http.sslCertPasswordProtected http.sslKey http.sslVerify + http.useragent i18n.commitEncoding i18n.logOutputEncoding + imap.authMethod imap.folder imap.host imap.pass @@ -1742,6 +2183,7 @@ _git_config () imap.sslverify imap.tunnel imap.user + init.templatedir instaweb.browser instaweb.httpd instaweb.local @@ -1749,19 +2191,29 @@ _git_config () instaweb.port interactive.singlekey log.date + log.decorate log.showroot mailmap.file man. man.viewer + merge. merge.conflictstyle merge.log merge.renameLimit + merge.renormalize merge.stat merge.tool merge.verbosity mergetool. mergetool.keepBackup + mergetool.keepTemporaries mergetool.prompt + notes.displayRef + notes.rewrite. + notes.rewrite.amend + notes.rewrite.rebase + notes.rewriteMode + notes.rewriteRef pack.compression pack.deltaCacheLimit pack.deltaCacheSize @@ -1772,31 +2224,42 @@ _git_config () pack.window pack.windowMemory pager. + pretty. pull.octopus pull.twohead push.default + rebase.autosquash rebase.stat + receive.autogc receive.denyCurrentBranch + receive.denyDeleteCurrent receive.denyDeletes receive.denyNonFastForwards receive.fsckObjects receive.unpackLimit + receive.updateserverinfo + remotes. repack.usedeltabaseoffset rerere.autoupdate rerere.enabled + sendemail. sendemail.aliasesfile - sendemail.aliasesfiletype + sendemail.aliasfiletype sendemail.bcc sendemail.cc sendemail.cccmd sendemail.chainreplyto sendemail.confirm sendemail.envelopesender + sendemail.from + sendemail.identity sendemail.multiedit sendemail.signedoffbycc + sendemail.smtpdomain sendemail.smtpencryption sendemail.smtppass sendemail.smtpserver + sendemail.smtpserveroption sendemail.smtpserverport sendemail.smtpuser sendemail.suppresscc @@ -1807,6 +2270,8 @@ _git_config () showbranch.default status.relativePaths status.showUntrackedFiles + status.submodulesummary + submodule. tar.umask transfer.unpackLimit url. @@ -1854,7 +2319,6 @@ _git_reset () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--merge --mixed --hard --soft --patch" @@ -1866,7 +2330,6 @@ _git_reset () _git_revert () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--edit --mainline --no-edit --no-commit --signoff" @@ -1880,7 +2343,6 @@ _git_rm () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp "--cached --dry-run --ignore-unmatch --quiet" @@ -1894,7 +2356,6 @@ _git_shortlog () { __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -1912,16 +2373,10 @@ _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=}" + --pretty=*|--format=*) + __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases) + " "" "${cur#*=}" return ;; --*) @@ -1936,7 +2391,6 @@ _git_show () _git_show_branch () { - local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) __gitcomp " @@ -1953,7 +2407,6 @@ _git_show_branch () _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")" @@ -1998,7 +2451,6 @@ _git_submodule () 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" @@ -2042,7 +2494,6 @@ _git_svn () --edit --rmdir --find-copies-harder --copy-similarity= " - local cur="${COMP_WORDS[COMP_CWORD]}" case "$subcommand,$cur" in fetch,--*) __gitcomp "--revision= --fetch-all $fc_opts" @@ -2114,8 +2565,8 @@ _git_svn () _git_tag () { local i c=1 f=0 - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" + while [ $c -lt $cword ]; do + i="${words[c]}" case "$i" in -d|-v) __gitcomp "$(__git_tags)" @@ -2128,7 +2579,7 @@ _git_tag () c=$((++c)) done - case "${COMP_WORDS[COMP_CWORD-1]}" in + case "$prev" in -m|-F) COMPREPLY=() ;; @@ -2145,12 +2596,28 @@ _git_tag () esac } +_git_whatchanged () +{ + _git_log +} + _git () { local i c=1 command __git_dir - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" + 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 + 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=}" ;; --bare) __git_dir="." ;; @@ -2162,7 +2629,7 @@ _git () done if [ -z "$command" ]; then - case "${COMP_WORDS[COMP_CWORD]}" in + case "$cur" in --*) __gitcomp " --paginate --no-pager @@ -2172,6 +2639,7 @@ _git () --exec-path --html-path --work-tree= + --namespace= --help " ;; @@ -2181,70 +2649,32 @@ _git () return fi + local completion_func="_git_${command//-/_}" + declare -f $completion_func >/dev/null && $completion_func && return + local expansion=$(__git_aliased_command "$command") - [ "$expansion" ] && command="$expansion" - - case "$command" in - am) _git_am ;; - add) _git_add ;; - apply) _git_apply ;; - archive) _git_archive ;; - bisect) _git_bisect ;; - bundle) _git_bundle ;; - branch) _git_branch ;; - checkout) _git_checkout ;; - cherry) _git_cherry ;; - cherry-pick) _git_cherry_pick ;; - clean) _git_clean ;; - clone) _git_clone ;; - commit) _git_commit ;; - config) _git_config ;; - describe) _git_describe ;; - diff) _git_diff ;; - difftool) _git_difftool ;; - fetch) _git_fetch ;; - format-patch) _git_format_patch ;; - fsck) _git_fsck ;; - gc) _git_gc ;; - grep) _git_grep ;; - help) _git_help ;; - init) _git_init ;; - log) _git_log ;; - ls-files) _git_ls_files ;; - ls-remote) _git_ls_remote ;; - ls-tree) _git_ls_tree ;; - merge) _git_merge;; - mergetool) _git_mergetool;; - merge-base) _git_merge_base ;; - mv) _git_mv ;; - name-rev) _git_name_rev ;; - pull) _git_pull ;; - push) _git_push ;; - rebase) _git_rebase ;; - remote) _git_remote ;; - replace) _git_replace ;; - reset) _git_reset ;; - revert) _git_revert ;; - rm) _git_rm ;; - send-email) _git_send_email ;; - shortlog) _git_shortlog ;; - show) _git_show ;; - show-branch) _git_show_branch ;; - stash) _git_stash ;; - stage) _git_add ;; - submodule) _git_submodule ;; - svn) _git_svn ;; - tag) _git_tag ;; - whatchanged) _git_log ;; - *) COMPREPLY=() ;; - esac + if [ -n "$expansion" ]; then + completion_func="_git_${expansion//-/_}" + declare -f $completion_func >/dev/null && $completion_func + fi } _gitk () { + 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 + fi + + local cur words cword prev + _get_comp_words_by_ref -n =: cur words cword prev + __git_has_doubledash && return - local cur="${COMP_WORDS[COMP_CWORD]}" local g="$(__gitdir)" local merge="" if [ -f "$g/MERGE_HEAD" ]; then @@ -2276,3 +2706,33 @@ 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 + +if [[ -n ${ZSH_VERSION-} ]]; then + __git_shopt () { + local option + if [ $# -ne 2 ]; then + echo "USAGE: $0 (-q|-s|-u) <option>" >&2 + return 1 + fi + case "$2" in + nullglob) + option="$2" + ;; + *) + echo "$0: invalid option: $2" >&2 + return 1 + esac + case "$1" in + -q) setopt | grep -q "$option" ;; + -u) unsetopt "$option" ;; + -s) setopt "$option" ;; + *) + echo "$0: invalid flag: $1" >&2 + return 1 + esac + } +else + __git_shopt () { + shopt "$@" + } +fi |