Merge branch 'pd/bash-4-completion'
authorJunio C Hamano <gitster@pobox.com>
Wed, 22 Dec 2010 22:40:55 +0000 (14:40 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 22 Dec 2010 22:40:55 +0000 (14:40 -0800)
* pd/bash-4-completion:
bash: simple reimplementation of _get_comp_words_by_ref
bash: get --pretty=m<tab> completion to work with bash v4

Conflicts:
contrib/completion/git-completion.bash

1  2 
contrib/completion/git-completion.bash
index 803da09a126ad75ad3578a90d117e13cef48ba46,d117055f56ea2200ebe6d23a558c7b654b1035cf..893b7716cafa4811d237480a980140d308aa20dc
@@@ -327,11 -327,168 +327,168 @@@ __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
+       _get_comp_words_by_ref -n =: cur
        if [ $# -gt 2 ]; then
                cur="$3"
        fi
@@@ -386,19 -543,17 +543,20 @@@ __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 i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
-       local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+       local cur format refs
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir" ]; then
                case "$cur" in
                refs|refs/*)
                        format="refname"
                        refs="${cur%/*}"
 +                      track=""
                        ;;
                *)
                        for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
                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
@@@ -506,7 -646,8 +664,8 @@@ __git_compute_merge_strategies (
  
  __git_complete_file ()
  {
-       local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
+       local pfx ls ref cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        ?*:*)
                ref="${cur%%:*}"
  
  __git_complete_revlist ()
  {
-       local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+       local pfx cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        *...*)
                pfx="${cur%...*}..."
  
  __git_complete_remote_or_refspec ()
  {
-       local cmd="${COMP_WORDS[1]}"
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
+       local 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)
  
  __git_complete_strategy ()
  {
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
        __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=}"
@@@ -735,6 -879,7 +897,6 @@@ __git_list_porcelain_commands (
                quiltimport)      : import;;
                read-tree)        : plumbing;;
                receive-pack)     : plumbing;;
 -              reflog)           : plumbing;;
                remote-*)         : transport;;
                repo-config)      : deprecated;;
                rerere)           : plumbing;;
@@@ -773,19 -918,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'
@@@ -824,10 -956,10 +986,10 @@@ __git_aliased_command (
  # __git_find_on_cmdline requires 1 argument
  __git_find_on_cmdline ()
  {
-       local word subcommand c=1
-       while [ $c -lt $COMP_CWORD ]; do
-               word="${COMP_WORDS[c]}"
+       local word subcommand c=1 words cword
+       _get_comp_words_by_ref -n =: words cword
+       while [ $c -lt $cword ]; do
+               word="${words[c]}"
                for subcommand in $1; do
                        if [ "$subcommand" = "$word" ]; then
                                echo "$subcommand"
  
  __git_has_doubledash ()
  {
-       local c=1
-       while [ $c -lt $COMP_CWORD ]; do
-               if [ "--" = "${COMP_WORDS[c]}" ]; then
+       local c=1 words cword
+       _get_comp_words_by_ref -n =: words cword
+       while [ $c -lt $cword ]; do
+               if [ "--" = "${words[c]}" ]; then
                        return 0
                fi
                c=$((++c))
@@@ -854,7 -987,8 +1017,8 @@@ __git_whitespacelist="nowarn warn erro
  
  _git_am ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+       local cur dir="$(__gitdir)"
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir"/rebase-apply ]; then
                __gitcomp "--skip --continue --resolved --abort"
                return
  
  _git_apply ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --whitespace=*)
                __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@@ -901,7 -1036,8 +1066,8 @@@ _git_add (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
  
  _git_archive ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --format=*)
                __gitcomp "$(git archive --list)" "" "${cur##--format=}"
@@@ -943,16 -1080,12 +1110,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)"
                ;;
        *)
  
  _git_branch ()
  {
-       local i c=1 only_local_ref="n" has_r="n"
+       local i c=1 only_local_ref="n" has_r="n" cur words cword
  
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       _get_comp_words_by_ref -n =: cur words cword
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                -d|-m)  only_local_ref="y" ;;
                -r)     has_r="y" ;;
                c=$((++c))
        done
  
-       case "${COMP_WORDS[COMP_CWORD]}" in
+       case "$cur" in
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
  
  _git_bundle ()
  {
-       local cmd="${COMP_WORDS[2]}"
-       case "$COMP_CWORD" in
+       local words cword
+       _get_comp_words_by_ref -n =: words cword
+       local cmd="${words[2]}"
+       case "$cword" in
        2)
                __gitcomp "create list-heads verify unbundle"
                ;;
@@@ -1016,7 -1152,8 +1186,8 @@@ _git_checkout (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --conflict=*)
                __gitcomp "diff3 merge" "" "${cur##--conflict=}"
                        "
                ;;
        *)
 -              __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
  }
@@@ -1046,7 -1177,8 +1217,8 @@@ _git_cherry (
  
  _git_cherry_pick ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--edit --no-commit"
@@@ -1061,7 -1193,8 +1233,8 @@@ _git_clean (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--dry-run --quiet"
  
  _git_clone ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@@ -1100,7 -1234,8 +1274,8 @@@ _git_commit (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --cleanup=*)
                __gitcomp "default strip verbatim whitespace
  
  _git_describe ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@@ -1167,7 -1303,8 +1343,8 @@@ _git_diff (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
@@@ -1188,7 -1325,8 +1365,8 @@@ _git_difftool (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --tool=*)
                __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
@@@ -1213,7 -1351,8 +1391,8 @@@ __git_fetch_options=
  
  _git_fetch ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "$__git_fetch_options"
  
  _git_format_patch ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --thread=*)
                __gitcomp "
  
  _git_fsck ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
  
  _git_gc ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--prune --aggressive"
@@@ -1291,7 -1433,8 +1473,8 @@@ _git_grep (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
  
  _git_help ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--all --info --man --web"
  
  _git_init ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --shared=*)
                __gitcomp "
@@@ -1352,7 -1497,8 +1537,8 @@@ _git_ls_files (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --deleted --modified --others --ignored
@@@ -1406,20 -1552,21 +1592,21 @@@ _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
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
 -              __gitcomp "$__git_log_pretty_formats
 +              __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
 -              __gitcomp "$__git_log_pretty_formats
 +              __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
@@@ -1465,7 -1612,8 +1652,8 @@@ _git_merge (
  {
        __git_complete_strategy && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "$__git_merge_options"
  
  _git_mergetool ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --tool=*)
                __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
@@@ -1497,7 -1646,8 +1686,8 @@@ _git_merge_base (
  
  _git_mv ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--dry-run"
@@@ -1514,50 -1664,20 +1704,51 @@@ _git_name_rev (
  
  _git_notes ()
  {
 -      local subcommands="edit show"
 -      local words cword
 -      _get_comp_words_by_ref -n =: words cword
 -      if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
 -              __gitcomp "$subcommands"
 -              return
 -      fi
 +      local subcommands='add append copy edit list prune remove show'
 +      local subcommand="$(__git_find_on_cmdline "$subcommands")"
-       local cur="${COMP_WORDS[COMP_CWORD]}"
++      local cur words cword
++      _get_comp_words_by_ref -n =: cur words cword
  
 -      case "${words[cword-1]}" in
 -      -m|-F)
 -              COMPREPLY=()
 +      case "$subcommand,$cur" in
 +      ,--*)
 +              __gitcomp '--ref'
 +              ;;
 +      ,*)
-               case "${COMP_WORDS[COMP_CWORD-1]}" in
++              case "${words[cword-1]}" in
 +              --ref)
 +                      __gitcomp "$(__git_refs)"
 +                      ;;
 +              *)
 +                      __gitcomp "$subcommands --ref"
 +                      ;;
 +              esac
 +              ;;
 +      add,--reuse-message=*|append,--reuse-message=*)
 +              __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
 +              ;;
 +      add,--reedit-message=*|append,--reedit-message=*)
 +              __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
 +              ;;
 +      add,--*|append,--*)
 +              __gitcomp '--file= --message= --reedit-message=
 +                              --reuse-message='
 +              ;;
 +      copy,--*)
 +              __gitcomp '--stdin'
 +              ;;
 +      prune,--*)
 +              __gitcomp '--dry-run --verbose'
 +              ;;
 +      prune,*)
                ;;
        *)
-               case "${COMP_WORDS[COMP_CWORD-1]}" in
 -              __gitcomp "$(__git_refs)"
++              case "${words[cword-1]}" in
 +              -m|-F)
 +                      ;;
 +              *)
 +                      __gitcomp "$(__git_refs)"
 +                      ;;
 +              esac
                ;;
        esac
  }
@@@ -1566,7 -1686,8 +1757,8 @@@ _git_pull (
  {
        __git_complete_strategy && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
  
  _git_push ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
+       case "$prev" in
        --repo)
                __gitcomp "$(__git_remotes)"
                return
  
  _git_rebase ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+       local dir="$(__gitdir)"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
                __gitcomp "--continue --skip --abort"
                return
        __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]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --confirm=*)
                __gitcomp "
@@@ -1690,9 -1803,11 +1886,11 @@@ _git_stage (
  
  __git_config_get_set_variables ()
  {
-       local prevword word config_file= c=$COMP_CWORD
+       local words cword
+       _get_comp_words_by_ref -n =: words 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"
  
  _git_config ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       local prv="${COMP_WORDS[COMP_CWORD-1]}"
-       case "$prv" in
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
+       case "$prev" in
        branch.*.remote)
                __gitcomp "$(__git_remotes)"
                return
                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)' \
                ;;
        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
                color.status.untracked
                color.status.updated
                color.ui
 +              commit.status
                commit.template
 +              core.abbrevguard
 +              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
                core.repositoryFormatVersion
                core.safecrlf
                core.sharedRepository
 +              core.sparseCheckout
                core.symlinks
                core.trustctime
                core.warnAmbiguousRefs
                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.subjectprefix
                format.suffix
                format.thread
 +              format.to
 +              gc.
                gc.aggressiveWindow
                gc.auto
                gc.autopacklimit
                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
                imap.sslverify
                imap.tunnel
                imap.user
 +              init.templatedir
                instaweb.browser
                instaweb.httpd
                instaweb.local
                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
                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
                showbranch.default
                status.relativePaths
                status.showUntrackedFiles
 +              status.submodulesummary
 +              submodule.
                tar.umask
                transfer.unpackLimit
                url.
@@@ -2191,7 -2244,8 +2389,8 @@@ _git_reset (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--merge --mixed --hard --soft --patch"
  
  _git_revert ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--edit --mainline --no-edit --no-commit --signoff"
@@@ -2217,7 -2272,8 +2417,8 @@@ _git_rm (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@@ -2231,7 -2287,8 +2432,8 @@@ _git_shortlog (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@@ -2249,15 -2306,16 +2451,16 @@@ _git_show (
  {
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
 -              __gitcomp "$__git_log_pretty_formats
 +              __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
 -              __gitcomp "$__git_log_pretty_formats
 +              __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
  
  _git_show_branch ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
  
  _git_stash ()
  {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        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")"
@@@ -2335,7 -2395,8 +2540,8 @@@ _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]}"
+               local cur
+               _get_comp_words_by_ref -n =: cur
                case "$cur" in
                --*)
                        __gitcomp "--quiet --cached"
@@@ -2379,7 -2440,8 +2585,8 @@@ _git_svn (
                        --edit --rmdir --find-copies-harder --copy-similarity=
                        "
  
-               local cur="${COMP_WORDS[COMP_CWORD]}"
+               local cur
+               _get_comp_words_by_ref -n =: cur
                case "$subcommand,$cur" in
                fetch,--*)
                        __gitcomp "--revision= --fetch-all $fc_opts"
  _git_tag ()
  {
        local i c=1 f=0
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       local words cword prev
+       _get_comp_words_by_ref -n =: words cword prev
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                -d|-v)
                        __gitcomp "$(__git_tags)"
                c=$((++c))
        done
  
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
+       case "$prev" in
        -m|-F)
                COMPREPLY=()
                ;;
@@@ -2496,8 -2560,10 +2705,10 @@@ _git (
                setopt KSH_TYPESET
        fi
  
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
                --bare)      __git_dir="." ;;
        done
  
        if [ -z "$command" ]; then
-               case "${COMP_WORDS[COMP_CWORD]}" in
+               case "$cur" in
                --*)   __gitcomp "
                        --paginate
                        --no-pager
@@@ -2547,12 -2613,13 +2758,13 @@@ _gitk (
  
        __git_has_doubledash && return
  
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
        local g="$(__gitdir)"
        local merge=""
        if [ -f "$g/MERGE_HEAD" ]; then
                merge="--merge"
        fi
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "