Merge branch 'bc/maint-keep-pack' into maint
[gitweb.git] / contrib / completion / git-completion.bash
index 3f46149853237fcded15d498f94b4ae3b174b79c..554a03ff4fbc61e8b02b6010c9ffb9fad632f195 100755 (executable)
 #       git@vger.kernel.org
 #
 
+case "$COMP_WORDBREAKS" in
+*:*) : great ;;
+*)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
+esac
+
 __gitdir ()
 {
        if [ -z "$1" ]; then
@@ -68,26 +73,26 @@ __git_ps1 ()
        if [ -n "$g" ]; then
                local r
                local b
-               if [ -d "$g/../.dotest" ]
+               if [ -d "$g/rebase-apply" ]
                then
-                       if test -f "$g/../.dotest/rebasing"
+                       if test -f "$g/rebase-apply/rebasing"
                        then
                                r="|REBASE"
-                       elif test -f "$g/../.dotest/applying"
+                       elif test -f "$g/rebase-apply/applying"
                        then
                                r="|AM"
                        else
                                r="|AM/REBASE"
                        fi
                        b="$(git symbolic-ref HEAD 2>/dev/null)"
-               elif [ -f "$g/.dotest-merge/interactive" ]
+               elif [ -f "$g/rebase-merge/interactive" ]
                then
                        r="|REBASE-i"
-                       b="$(cat "$g/.dotest-merge/head-name")"
-               elif [ -d "$g/.dotest-merge" ]
+                       b="$(cat "$g/rebase-merge/head-name")"
+               elif [ -d "$g/rebase-merge" ]
                then
                        r="|REBASE-m"
-                       b="$(cat "$g/.dotest-merge/head-name")"
+                       b="$(cat "$g/rebase-merge/head-name")"
                elif [ -f "$g/MERGE_HEAD" ]
                then
                        r="|MERGING"
@@ -114,9 +119,20 @@ __git_ps1 ()
        fi
 }
 
+__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
+}
+
 __gitcomp ()
 {
-       local all c s=$'\n' IFS=' '$'\t'$'\n'
        local cur="${COMP_WORDS[COMP_CWORD]}"
        if [ $# -gt 2 ]; then
                cur="$3"
@@ -124,21 +140,14 @@ __gitcomp ()
        case "$cur" in
        --*=)
                COMPREPLY=()
-               return
                ;;
        *)
-               for c in $1; do
-                       case "$c$4" in
-                       --*=*) all="$all$c$4$s" ;;
-                       *.)    all="$all$c$4$s" ;;
-                       *)     all="$all$c$4 $s" ;;
-                       esac
-               done
+               local IFS=$'\n'
+               COMPREPLY=($(compgen -P "$2" \
+                       -W "$(__gitcomp_1 "$1" "$4")" \
+                       -- "$cur"))
                ;;
        esac
-       IFS=$s
-       COMPREPLY=($(compgen -P "$2" -W "$all" -- "$cur"))
-       return
 }
 
 __git_heads ()
@@ -262,15 +271,17 @@ __git_merge_strategies ()
                echo "$__git_merge_strategylist"
                return
        fi
-       sed -n "/^all_strategies='/{
-               s/^all_strategies='//
-               s/'//
+       git merge -s help 2>&1 |
+       sed -n -e '/[Aa]vailable strategies are: /,/^$/{
+               s/\.$//
+               s/.*://
+               s/^[    ]*//
+               s/[     ]*$//
                p
-               q
-               }" "$(git --exec-path)/git-merge"
+       }'
 }
 __git_merge_strategylist=
-__git_merge_strategylist="$(__git_merge_strategies 2>/dev/null)"
+__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)
 
 __git_complete_file ()
 {
@@ -290,9 +301,23 @@ __git_complete_file ()
                        ls="$ref"
                        ;;
            esac
+
+               case "$COMP_WORDBREAKS" in
+               *:*) : great ;;
+               *)   pfx="$ref:$pfx" ;;
+               esac
+
+               local IFS=$'\n'
                COMPREPLY=($(compgen -P "$pfx" \
                        -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
-                               | sed '/^100... blob /s,^.*     ,,
+                               | sed '/^100... blob /{
+                                          s,^.*        ,,
+                                          s,$, ,
+                                      }
+                                      /^120000 blob /{
+                                          s,^.*        ,,
+                                          s,$, ,
+                                      }
                                       /^040000 tree /{
                                           s,^.*        ,,
                                           s,$,/,
@@ -320,23 +345,38 @@ __git_complete_revlist ()
                cur="${cur#*..}"
                __gitcomp "$(__git_refs)" "$pfx" "$cur"
                ;;
-       *.)
-               __gitcomp "$cur."
-               ;;
        *)
                __gitcomp "$(__git_refs)"
                ;;
        esac
 }
 
-__git_commands ()
+__git_all_commands ()
 {
-       if [ -n "$__git_commandlist" ]; then
-               echo "$__git_commandlist"
+       if [ -n "$__git_all_commandlist" ]; then
+               echo "$__git_all_commandlist"
                return
        fi
        local i IFS=" "$'\n'
        for i in $(git help -a|egrep '^ ')
+       do
+               case $i in
+               *--*)             : helper pattern;;
+               *) echo $i;;
+               esac
+       done
+}
+__git_all_commandlist=
+__git_all_commandlist="$(__git_all_commands 2>/dev/null)"
+
+__git_porcelain_commands ()
+{
+       if [ -n "$__git_porcelain_commandlist" ]; then
+               echo "$__git_porcelain_commandlist"
+               return
+       fi
+       local i IFS=" "$'\n'
+       for i in "help" $(__git_all_commands)
        do
                case $i in
                *--*)             : helper pattern;;
@@ -346,7 +386,9 @@ __git_commands ()
                cat-file)         : plumbing;;
                check-attr)       : plumbing;;
                check-ref-format) : plumbing;;
+               checkout-index)   : plumbing;;
                commit-tree)      : plumbing;;
+               count-objects)    : infrequent;;
                cvsexportcommit)  : export;;
                cvsimport)        : import;;
                cvsserver)        : daemon;;
@@ -355,6 +397,7 @@ __git_commands ()
                diff-index)       : plumbing;;
                diff-tree)        : plumbing;;
                fast-import)      : import;;
+               fast-export)      : export;;
                fsck-objects)     : plumbing;;
                fetch-pack)       : plumbing;;
                fmt-merge-msg)    : plumbing;;
@@ -364,6 +407,10 @@ __git_commands ()
                index-pack)       : plumbing;;
                init-db)          : deprecated;;
                local-fetch)      : plumbing;;
+               lost-found)       : infrequent;;
+               ls-files)         : plumbing;;
+               ls-remote)        : plumbing;;
+               ls-tree)          : plumbing;;
                mailinfo)         : plumbing;;
                mailsplit)        : plumbing;;
                merge-*)          : plumbing;;
@@ -388,6 +435,7 @@ __git_commands ()
                runstatus)        : plumbing;;
                sh-setup)         : internal;;
                shell)            : daemon;;
+               show-ref)         : plumbing;;
                send-pack)        : plumbing;;
                show-index)       : plumbing;;
                ssh-*)            : transport;;
@@ -402,13 +450,15 @@ __git_commands ()
                upload-archive)   : plumbing;;
                upload-pack)      : plumbing;;
                write-tree)       : plumbing;;
+               var)              : infrequent;;
+               verify-pack)      : infrequent;;
                verify-tag)       : plumbing;;
                *) echo $i;;
                esac
        done
 }
-__git_commandlist=
-__git_commandlist="$(__git_commands 2>/dev/null)"
+__git_porcelain_commandlist=
+__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
 
 __git_aliases ()
 {
@@ -451,13 +501,25 @@ __git_find_subcommand ()
        done
 }
 
-__git_whitespacelist="nowarn warn error error-all strip"
+__git_has_doubledash ()
+{
+       local c=1
+       while [ $c -lt $COMP_CWORD ]; do
+               if [ "--" = "${COMP_WORDS[c]}" ]; then
+                       return 0
+               fi
+               c=$((++c))
+       done
+       return 1
+}
+
+__git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       if [ -d .dotest ]; then
-               __gitcomp "--skip --resolved"
+       local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+       if [ -d "$dir"/rebase-apply ]; then
+               __gitcomp "--skip --resolved --abort"
                return
        fi
        case "$cur" in
@@ -497,6 +559,8 @@ _git_apply ()
 
 _git_add ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
@@ -509,9 +573,34 @@ _git_add ()
        COMPREPLY=()
 }
 
+_git_archive ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --format=*)
+               __gitcomp "$(git archive --list)" "" "${cur##--format=}"
+               return
+               ;;
+       --remote=*)
+               __gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
+               return
+               ;;
+       --*)
+               __gitcomp "
+                       --format= --list --verbose
+                       --prefix= --remote= --exec=
+                       "
+               return
+               ;;
+       esac
+       __git_complete_file
+}
+
 _git_bisect ()
 {
-       local subcommands="start bad good reset visualize replay log"
+       __git_has_doubledash && return
+
+       local subcommands="start bad good skip reset visualize replay log run"
        local subcommand="$(__git_find_subcommand "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
@@ -519,7 +608,7 @@ _git_bisect ()
        fi
 
        case "$subcommand" in
-       bad|good|reset)
+       bad|good|reset|skip)
                __gitcomp "$(__git_refs)"
                ;;
        *)
@@ -546,7 +635,7 @@ _git_branch ()
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
-                       --track --no-track
+                       --track --no-track --contains --merged --no-merged
                        "
                ;;
        *)
@@ -561,21 +650,12 @@ _git_branch ()
 
 _git_bundle ()
 {
-       local mycword="$COMP_CWORD"
-       case "${COMP_WORDS[0]}" in
-       git)
-               local cmd="${COMP_WORDS[2]}"
-               mycword="$((mycword-1))"
-               ;;
-       git-bundle*)
-               local cmd="${COMP_WORDS[1]}"
-               ;;
-       esac
-       case "$mycword" in
-       1)
+       local cmd="${COMP_WORDS[2]}"
+       case "$COMP_CWORD" in
+       2)
                __gitcomp "create list-heads verify unbundle"
                ;;
-       2)
+       3)
                # looking for a file
                ;;
        *)
@@ -590,6 +670,8 @@ _git_bundle ()
 
 _git_checkout ()
 {
+       __git_has_doubledash && return
+
        __gitcomp "$(__git_refs)"
 }
 
@@ -611,14 +693,55 @@ _git_cherry_pick ()
        esac
 }
 
+_git_clean ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--dry-run --quiet"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
+_git_clone ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --local
+                       --no-hardlinks
+                       --shared
+                       --reference
+                       --quiet
+                       --no-checkout
+                       --bare
+                       --mirror
+                       --origin
+                       --upload-pack
+                       --template=
+                       --depth
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_commit ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
                __gitcomp "
                        --all --author= --signoff --verify --no-verify
-                       --edit --amend --include --only
+                       --edit --amend --include --only --interactive
                        "
                return
        esac
@@ -627,18 +750,29 @@ _git_commit ()
 
 _git_describe ()
 {
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --all --tags --contains --abbrev= --candidates=
+                       --exact-match --debug --long --match --always
+                       "
+               return
+       esac
        __gitcomp "$(__git_refs)"
 }
 
 _git_diff ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
                __gitcomp "--cached --stat --numstat --shortstat --summary
                        --patch-with-stat --name-only --name-status --color
                        --no-color --color-words --no-renames --check
-                       --full-index --binary --abbrev --diff-filter
+                       --full-index --binary --abbrev --diff-filter=
                        --find-copies-harder --pickaxe-all --pickaxe-regex
                        --text --ignore-space-at-eol --ignore-space-change
                        --ignore-all-space --exit-code --quiet --ext-diff
@@ -652,38 +786,27 @@ _git_diff ()
        __git_complete_file
 }
 
-_git_diff_tree ()
-{
-       __gitcomp "$(__git_refs)"
-}
-
 _git_fetch ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-fetch*,1)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       *)
+       else
                case "$cur" in
                *:*)
-                       __gitcomp "$(__git_refs)" "" "${cur#*:}"
+                       local pfx=""
+                       case "$COMP_WORDBREAKS" in
+                       *:*) : great ;;
+                       *)   pfx="${cur%%:*}:" ;;
+                       esac
+                       __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}"
                        ;;
                *)
-                       local remote
-                       case "${COMP_WORDS[0]}" in
-                       git-fetch) remote="${COMP_WORDS[1]}" ;;
-                       git)       remote="${COMP_WORDS[2]}" ;;
-                       esac
-                       __gitcomp "$(__git_refs2 "$remote")"
+                       __gitcomp "$(__git_refs2 "${COMP_WORDS[2]}")"
                        ;;
                esac
-               ;;
-       esac
+       fi
 }
 
 _git_format_patch ()
@@ -722,6 +845,83 @@ _git_gc ()
        COMPREPLY=()
 }
 
+_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
+                       --extended-regexp --basic-regexp --fixed-strings
+                       --files-with-matches --name-only
+                       --files-without-match
+                       --count
+                       --and --or --not --all-match
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
+_git_help ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--all --info --man --web"
+               return
+               ;;
+       esac
+       __gitcomp "$(__git_all_commands)
+               attributes cli core-tutorial cvs-migration
+               diffcore gitk glossary hooks ignore modules
+               repository-layout tutorial tutorial-2
+               "
+}
+
+_git_init ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --shared=*)
+               __gitcomp "
+                       false true umask group all world everybody
+                       " "" "${cur##--shared=}"
+               return
+               ;;
+       --*)
+               __gitcomp "--quiet --bare --template= --shared --shared="
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
+_git_ls_files ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--cached --deleted --modified --others --ignored
+                       --stage --directory --no-empty-directory --unmerged
+                       --killed --exclude= --exclude-from=
+                       --exclude-per-directory= --exclude-standard
+                       --error-unmatch --with-tree= --full-name
+                       --abbrev --ignored --exclude-per-directory
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_ls_remote ()
 {
        __gitcomp "$(__git_remotes)"
@@ -734,6 +934,8 @@ _git_ls_tree ()
 
 _git_log ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
@@ -765,6 +967,8 @@ _git_log ()
                        --stat --numstat --shortstat
                        --decorate --diff-filter=
                        --color-words --walk-reflogs
+                       --parents --children --full-history
+                       --merge
                        "
                return
                ;;
@@ -794,11 +998,42 @@ _git_merge ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_mergetool ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --tool=*)
+               __gitcomp "
+                       kdiff3 tkdiff meld xxdiff emerge
+                       vimdiff gvimdiff ecmerge opendiff
+                       " "" "${cur##--tool=}"
+               return
+               ;;
+       --*)
+               __gitcomp "--tool="
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_merge_base ()
 {
        __gitcomp "$(__git_refs)"
 }
 
+_git_mv ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--dry-run"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_name_rev ()
 {
        __gitcomp "--tags --all --stdin"
@@ -808,44 +1043,29 @@ _git_pull ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-pull*,1)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       *)
-               local remote
-               case "${COMP_WORDS[0]}" in
-               git-pull)  remote="${COMP_WORDS[1]}" ;;
-               git)       remote="${COMP_WORDS[2]}" ;;
-               esac
-               __gitcomp "$(__git_refs "$remote")"
-               ;;
-       esac
+       else
+               __gitcomp "$(__git_refs "${COMP_WORDS[2]}")"
+       fi
 }
 
 _git_push ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-push*,1)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       *)
+       else
                case "$cur" in
                *:*)
-                       local remote
-                       case "${COMP_WORDS[0]}" in
-                       git-push)  remote="${COMP_WORDS[1]}" ;;
-                       git)       remote="${COMP_WORDS[2]}" ;;
+                       local pfx=""
+                       case "$COMP_WORDBREAKS" in
+                       *:*) : great ;;
+                       *)   pfx="${cur%%:*}:" ;;
                        esac
-                       __gitcomp "$(__git_refs "$remote")" "" "${cur#*:}"
+
+                       __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" "$pfx" "${cur#*:}"
                        ;;
                +*)
                        __gitcomp "$(__git_refs)" + "${cur#+}"
@@ -854,14 +1074,13 @@ _git_push ()
                        __gitcomp "$(__git_refs)"
                        ;;
                esac
-               ;;
-       esac
+       fi
 }
 
 _git_rebase ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
-       if [ -d .dotest ] || [ -d "$dir"/.dotest-merge ]; then
+       if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
                __gitcomp "--continue --skip --abort"
                return
        fi
@@ -882,6 +1101,24 @@ _git_rebase ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_send_email ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--bcc --cc --cc-cmd --chain-reply-to --compose
+                       --dry-run --envelope-sender --from --identity
+                       --in-reply-to --no-chain-reply-to --no-signed-off-by-cc
+                       --no-suppress-from --no-thread --quiet
+                       --signed-off-by-cc --smtp-pass --smtp-server
+                       --smtp-server-port --smtp-ssl --smtp-user --subject
+                       --suppress-cc --suppress-from --thread --to"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_config ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -1086,6 +1323,8 @@ _git_remote ()
 
 _git_reset ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
@@ -1096,8 +1335,36 @@ _git_reset ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_revert ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--edit --mainline --no-edit --no-commit --signoff"
+               return
+               ;;
+       esac
+       __gitcomp "$(__git_refs)"
+}
+
+_git_rm ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--cached --dry-run --ignore-unmatch --quiet"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_shortlog ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
@@ -1118,6 +1385,8 @@ _git_shortlog ()
 
 _git_show ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
@@ -1134,16 +1403,55 @@ _git_show ()
        __git_complete_file
 }
 
+_git_show_branch ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --all --remotes --topo-order --current --more=
+                       --list --independent --merge-base --no-name
+                       --sha1-name --topics --reflog
+                       "
+               return
+               ;;
+       esac
+       __git_complete_revlist
+}
+
 _git_stash ()
 {
-       local subcommands='save list show apply clear drop pop create'
-       if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
+       local subcommands='save list show apply clear drop pop create branch'
+       local subcommand="$(__git_find_subcommand "$subcommands")"
+       if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
+       else
+               local cur="${COMP_WORDS[COMP_CWORD]}"
+               case "$subcommand,$cur" in
+               save,--*)
+                       __gitcomp "--keep-index"
+                       ;;
+               apply,--*)
+                       __gitcomp "--index"
+                       ;;
+               show,--*|drop,--*|pop,--*|branch,--*)
+                       COMPREPLY=()
+                       ;;
+               show,*|apply,*|drop,*|pop,*|branch,*)
+                       __gitcomp "$(git --git-dir="$(__gitdir)" stash list \
+                                       | sed -n -e 's/:.*//p')"
+                       ;;
+               *)
+                       COMPREPLY=()
+                       ;;
+               esac
        fi
 }
 
 _git_submodule ()
 {
+       __git_has_doubledash && return
+
        local subcommands="add status init update"
        if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
                local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -1258,7 +1566,7 @@ _git_tag ()
        -m|-F)
                COMPREPLY=()
                ;;
-       -*|tag|git-tag)
+       -*|tag)
                if [ $f = 1 ]; then
                        __gitcomp "$(__git_tags)"
                else
@@ -1280,7 +1588,8 @@ _git ()
                case "$i" in
                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
                --bare)      __git_dir="." ;;
-               --version|--help|-p|--paginate) ;;
+               --version|-p|--paginate) ;;
+               --help) command="help"; break ;;
                *) command="$i"; break ;;
                esac
                c=$((++c))
@@ -1300,7 +1609,7 @@ _git ()
                        --help
                        "
                        ;;
-               *)     __gitcomp "$(__git_commands) $(__git_aliases)" ;;
+               *)     __gitcomp "$(__git_porcelain_commands) $(__git_aliases)" ;;
                esac
                return
        fi
@@ -1312,12 +1621,15 @@ _git ()
        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 ;;
@@ -1325,20 +1637,29 @@ _git ()
        fetch)       _git_fetch ;;
        format-patch) _git_format_patch ;;
        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 ;;
        reset)       _git_reset ;;
+       revert)      _git_revert ;;
+       rm)          _git_rm ;;
+       send-email)  _git_send_email ;;
        shortlog)    _git_shortlog ;;
        show)        _git_show ;;
-       show-branch) _git_log ;;
+       show-branch) _git_show_branch ;;
        stash)       _git_stash ;;
        submodule)   _git_submodule ;;
        svn)         _git_svn ;;
@@ -1350,6 +1671,8 @@ _git ()
 
 _gitk ()
 {
+       __git_has_doubledash && return
+
        local cur="${COMP_WORDS[COMP_CWORD]}"
        local g="$(git rev-parse --git-dir 2>/dev/null)"
        local merge=""
@@ -1367,64 +1690,11 @@ _gitk ()
 
 complete -o default -o nospace -F _git git
 complete -o default -o nospace -F _gitk gitk
-complete -o default -o nospace -F _git_am git-am
-complete -o default -o nospace -F _git_apply git-apply
-complete -o default -o nospace -F _git_bisect git-bisect
-complete -o default -o nospace -F _git_branch git-branch
-complete -o default -o nospace -F _git_bundle git-bundle
-complete -o default -o nospace -F _git_checkout git-checkout
-complete -o default -o nospace -F _git_cherry git-cherry
-complete -o default -o nospace -F _git_cherry_pick git-cherry-pick
-complete -o default -o nospace -F _git_commit git-commit
-complete -o default -o nospace -F _git_describe git-describe
-complete -o default -o nospace -F _git_diff git-diff
-complete -o default -o nospace -F _git_fetch git-fetch
-complete -o default -o nospace -F _git_format_patch git-format-patch
-complete -o default -o nospace -F _git_gc git-gc
-complete -o default -o nospace -F _git_log git-log
-complete -o default -o nospace -F _git_ls_remote git-ls-remote
-complete -o default -o nospace -F _git_ls_tree git-ls-tree
-complete -o default -o nospace -F _git_merge git-merge
-complete -o default -o nospace -F _git_merge_base git-merge-base
-complete -o default -o nospace -F _git_name_rev git-name-rev
-complete -o default -o nospace -F _git_pull git-pull
-complete -o default -o nospace -F _git_push git-push
-complete -o default -o nospace -F _git_rebase git-rebase
-complete -o default -o nospace -F _git_config git-config
-complete -o default -o nospace -F _git_remote git-remote
-complete -o default -o nospace -F _git_reset git-reset
-complete -o default -o nospace -F _git_shortlog git-shortlog
-complete -o default -o nospace -F _git_show git-show
-complete -o default -o nospace -F _git_stash git-stash
-complete -o default -o nospace -F _git_submodule git-submodule
-complete -o default -o nospace -F _git_svn git-svn
-complete -o default -o nospace -F _git_log git-show-branch
-complete -o default -o nospace -F _git_tag git-tag
-complete -o default -o nospace -F _git_log git-whatchanged
 
 # 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 default -o nospace -F _git_add git-add.exe
-complete -o default -o nospace -F _git_apply git-apply.exe
 complete -o default -o nospace -F _git git.exe
-complete -o default -o nospace -F _git_branch git-branch.exe
-complete -o default -o nospace -F _git_bundle git-bundle.exe
-complete -o default -o nospace -F _git_cherry git-cherry.exe
-complete -o default -o nospace -F _git_describe git-describe.exe
-complete -o default -o nospace -F _git_diff git-diff.exe
-complete -o default -o nospace -F _git_format_patch git-format-patch.exe
-complete -o default -o nospace -F _git_log git-log.exe
-complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
-complete -o default -o nospace -F _git_merge_base git-merge-base.exe
-complete -o default -o nospace -F _git_name_rev git-name-rev.exe
-complete -o default -o nospace -F _git_push git-push.exe
-complete -o default -o nospace -F _git_config git-config
-complete -o default -o nospace -F _git_shortlog git-shortlog.exe
-complete -o default -o nospace -F _git_show git-show.exe
-complete -o default -o nospace -F _git_log git-show-branch.exe
-complete -o default -o nospace -F _git_tag git-tag.exe
-complete -o default -o nospace -F _git_log git-whatchanged.exe
 fi