t4020: abstract away SHA-1-specific constants
[gitweb.git] / contrib / completion / git-completion.bash
index e76b2f0356ac84224ae0affcfbb48a5ff75af604..46047e17ece55f5fb1768e34d54b49c3841b3e58 100644 (file)
@@ -29,6 +29,8 @@
 # tell the completion to use commit completion.  This also works with aliases
 # of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".
 #
+# Compatible with bash 3.2.57.
+#
 # You can set the following environment variables to influence the behavior of
 # the completion routines:
 #
@@ -280,6 +282,14 @@ __gitcomp ()
        esac
 }
 
+# Clear the variables caching builtins' options when (re-)sourcing
+# the completion script.
+if [[ -n ${ZSH_VERSION-} ]]; then
+       unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null
+else
+       unset $(compgen -v __gitcomp_builtin_)
+fi
+
 # This function is equivalent to
 #
 #    __gitcomp "$(git xxx --git-completion-helper) ..."
@@ -384,12 +394,7 @@ __git_index_files ()
        local root="${2-.}" file
 
        __git_ls_files_helper "$root" "$1" |
-       while read -r file; do
-               case "$file" in
-               ?*/*) echo "${file%%/*}" ;;
-               *) echo "$file" ;;
-               esac
-       done | sort | uniq
+       cut -f1 -d/ | sort | uniq
 }
 
 # Lists branches from the local repository.
@@ -472,7 +477,7 @@ __git_refs ()
                        track=""
                        ;;
                *)
-                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
                                case "$i" in
                                $match*)
                                        if [ -e "$dir/$i" ]; then
@@ -627,7 +632,7 @@ __git_is_configured_remote ()
 
 __git_list_merge_strategies ()
 {
-       git merge -s help 2>&1 |
+       LANG=C LC_ALL=C git merge -s help 2>&1 |
        sed -n -e '/[Aa]vailable strategies are: /,/^$/{
                s/\.$//
                s/.*://
@@ -874,6 +879,7 @@ __git_list_porcelain_commands ()
                check-ref-format) : plumbing;;
                checkout-index)   : plumbing;;
                column)           : internal helper;;
+               commit-graph)     : plumbing;;
                commit-tree)      : plumbing;;
                count-objects)    : infrequent;;
                credential)       : credentials;;
@@ -1105,7 +1111,7 @@ __git_count_arguments ()
 }
 
 __git_whitespacelist="nowarn warn error error-all fix"
-__git_am_inprogress_options="--skip --continue --resolved --abort"
+__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch"
 
 _git_am ()
 {
@@ -1280,6 +1286,12 @@ _git_checkout ()
 
 _git_cherry ()
 {
+       case "$cur" in
+       --*)
+               __gitcomp_builtin cherry
+               return
+       esac
+
        __git_complete_refs
 }
 
@@ -1499,16 +1511,6 @@ _git_fsck ()
        esac
 }
 
-_git_gc ()
-{
-       case "$cur" in
-       --*)
-               __gitcomp_builtin gc
-               return
-               ;;
-       esac
-}
-
 _git_gitk ()
 {
        _gitk
@@ -1633,6 +1635,13 @@ _git_ls_remote ()
 
 _git_ls_tree ()
 {
+       case "$cur" in
+       --*)
+               __gitcomp_builtin ls-tree
+               return
+               ;;
+       esac
+
        __git_complete_file
 }
 
@@ -1754,8 +1763,7 @@ _git_merge ()
 
        case "$cur" in
        --*)
-               __gitcomp_builtin merge "--rerere-autoupdate
-                               --no-rerere-autoupdate
+               __gitcomp_builtin merge "--no-rerere-autoupdate
                                --no-commit --no-edit --no-ff
                                --no-log --no-progress
                                --no-squash --no-stat
@@ -1809,14 +1817,9 @@ _git_mv ()
        fi
 }
 
-_git_name_rev ()
-{
-       __gitcomp_builtin name-rev
-}
-
 _git_notes ()
 {
-       local subcommands='add append copy edit list prune remove show'
+       local subcommands='add append copy edit get-ref list merge prune remove show'
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
 
        case "$subcommand,$cur" in
@@ -1833,23 +1836,14 @@ _git_notes ()
                        ;;
                esac
                ;;
-       add,--reuse-message=*|append,--reuse-message=*|\
-       add,--reedit-message=*|append,--reedit-message=*)
+       *,--reuse-message=*|*,--reedit-message=*)
                __git_complete_refs --cur="${cur#*=}"
                ;;
-       add,--*)
-               __gitcomp_builtin notes_add
+       *,--*)
+               __gitcomp_builtin notes_$subcommand
                ;;
-       append,--*)
-               __gitcomp_builtin notes_append
-               ;;
-       copy,--*)
-               __gitcomp_builtin notes_copy
-               ;;
-       prune,--*)
-               __gitcomp_builtin notes_prune
-               ;;
-       prune,*)
+       prune,*|get-ref,*)
+               # this command does not take a ref, do not complete it
                ;;
        *)
                case "$prev" in
@@ -1939,11 +1933,11 @@ _git_rebase ()
 {
        __git_find_repo_path
        if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then
-               __gitcomp "--continue --skip --abort --quit --edit-todo"
+               __gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch"
                return
        elif [ -d "$__git_repo_path"/rebase-apply ] || \
             [ -d "$__git_repo_path"/rebase-merge ]; then
-               __gitcomp "--continue --skip --abort --quit"
+               __gitcomp "--continue --skip --abort --quit --show-current-patch"
                return
        fi
        __git_complete_strategy && return
@@ -1963,6 +1957,7 @@ _git_rebase ()
                        --autostash --no-autostash
                        --verify --no-verify
                        --keep-empty --root --force-rebase --no-ff
+                       --rerere-autoupdate
                        --exec
                        "
 
@@ -2028,7 +2023,7 @@ _git_send_email ()
                        --compose --confirm= --dry-run --envelope-sender
                        --from --identity
                        --in-reply-to --no-chain-reply-to --no-signed-off-by-cc
-                       --no-suppress-from --no-thread --quiet
+                       --no-suppress-from --no-thread --quiet --reply-to
                        --signed-off-by-cc --smtp-pass --smtp-server
                        --smtp-server-port --smtp-encryption= --smtp-user
                        --subject --suppress-cc= --suppress-from --thread --to
@@ -2355,6 +2350,7 @@ _git_config ()
                core.bigFileThreshold
                core.checkStat
                core.commentChar
+               core.commitGraph
                core.compression
                core.createObject
                core.deltaBaseCacheLimit
@@ -2779,13 +2775,21 @@ _git_show_branch ()
 _git_stash ()
 {
        local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked'
-       local subcommands='push save list show apply clear drop pop create branch'
-       local subcommand="$(__git_find_on_cmdline "$subcommands")"
+       local subcommands='push list show apply clear drop pop create branch'
+       local subcommand="$(__git_find_on_cmdline "$subcommands save")"
+       if [ -n "$(__git_find_on_cmdline "-p")" ]; then
+               subcommand="push"
+       fi
        if [ -z "$subcommand" ]; then
                case "$cur" in
                --*)
                        __gitcomp "$save_opts"
                        ;;
+               sa*)
+                       if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
+                               __gitcomp "save"
+                       fi
+                       ;;
                *)
                        if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
                                __gitcomp "$subcommands"
@@ -2976,7 +2980,7 @@ _git_tag ()
        while [ $c -lt $cword ]; do
                i="${words[c]}"
                case "$i" in
-               -d|-v)
+               -d|--delete|-v|--verify)
                        __gitcomp_direct "$(__git_tags "" "$cur" " ")"
                        return
                        ;;
@@ -3014,23 +3018,26 @@ _git_whatchanged ()
 
 _git_worktree ()
 {
-       local subcommands="add list lock prune unlock"
+       local subcommands="add list lock move prune remove unlock"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
        else
                case "$subcommand,$cur" in
                add,--*)
-                       __gitcomp "--detach"
+                       __gitcomp_builtin worktree_add
                        ;;
                list,--*)
-                       __gitcomp "--porcelain"
+                       __gitcomp_builtin worktree_list
                        ;;
                lock,--*)
-                       __gitcomp "--reason"
+                       __gitcomp_builtin worktree_lock
                        ;;
                prune,--*)
-                       __gitcomp "--dry-run --expire --verbose"
+                       __gitcomp_builtin worktree_prune
+                       ;;
+               remove,--*)
+                       __gitcomp "--force"
                        ;;
                *)
                        ;;
@@ -3038,6 +3045,45 @@ _git_worktree ()
        fi
 }
 
+__git_complete_common () {
+       local command="$1"
+
+       case "$cur" in
+       --*)
+               __gitcomp_builtin "$command"
+               ;;
+       esac
+}
+
+__git_cmds_with_parseopt_helper=
+__git_support_parseopt_helper () {
+       test -n "$__git_cmds_with_parseopt_helper" ||
+               __git_cmds_with_parseopt_helper="$(__git --list-parseopt-builtins)"
+
+       case " $__git_cmds_with_parseopt_helper " in
+       *" $1 "*)
+               return 0
+               ;;
+       *)
+               return 1
+               ;;
+       esac
+}
+
+__git_complete_command () {
+       local command="$1"
+       local completion_func="_git_${command//-/_}"
+       if declare -f $completion_func >/dev/null 2>/dev/null; then
+               $completion_func
+               return 0
+       elif __git_support_parseopt_helper "$command"; then
+               __git_complete_common "$command"
+               return 0
+       else
+               return 1
+       fi
+}
+
 __git_main ()
 {
        local i c=1 command __git_dir __git_repo_path
@@ -3097,14 +3143,12 @@ __git_main ()
                return
        fi
 
-       local completion_func="_git_${command//-/_}"
-       declare -f $completion_func >/dev/null 2>/dev/null && $completion_func && return
+       __git_complete_command "$command" && return
 
        local expansion=$(__git_aliased_command "$command")
        if [ -n "$expansion" ]; then
                words[1]=$expansion
-               completion_func="_git_${expansion//-/_}"
-               declare -f $completion_func >/dev/null 2>/dev/null && $completion_func
+               __git_complete_command "$expansion"
        fi
 }