Merge branch 'maint'
[gitweb.git] / contrib / completion / git-completion.bash
index e00454983ee16624910e40fec9ddb12849110b1b..f44f63cfebf68f773dd96bd82317801d468f6cff 100755 (executable)
@@ -1,3 +1,4 @@
+#!bash
 #
 # bash completion support for core Git.
 #
 #       are currently in a git repository.  The %s token will be
 #       the name of the current branch.
 #
+#       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
+#       value, unstaged (*) and staged (+) changes will be shown next
+#       to the branch name.  You can configure this per-repository
+#       with the bash.showDirtyState variable, which defaults to true
+#       once GIT_PS1_SHOWDIRTYSTATE is enabled.
+#
 # To submit patches:
 #
 #    *) Read Documentation/SubmittingPatches
@@ -50,9 +57,11 @@ case "$COMP_WORDBREAKS" in
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
 esac
 
+# __gitdir accepts 0 or 1 arguments (i.e., location)
+# returns location of .git repo
 __gitdir ()
 {
-       if [ -z "$1" ]; then
+       if [ -z "${1-}" ]; then
                if [ -n "$__git_dir" ]; then
                        echo "$__git_dir"
                elif [ -d .git ]; then
@@ -67,6 +76,8 @@ __gitdir ()
        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="$(git rev-parse --git-dir 2>/dev/null)"
@@ -111,14 +122,31 @@ __git_ps1 ()
                        fi
                fi
 
-               if [ -n "$1" ]; then
-                       printf "$1" "${b##refs/heads/}$r"
+               local w
+               local i
+
+               if test -n "${GIT_PS1_SHOWDIRTYSTATE-}"; then
+                       if test "$(git config --bool bash.showDirtyState)" != "false"; then
+                               git diff --no-ext-diff --ignore-submodules \
+                                       --quiet --exit-code || w="*"
+                               if git rev-parse --quiet --verify HEAD >/dev/null; then
+                                       git diff-index --cached --quiet \
+                                               --ignore-submodules HEAD -- || i="+"
+                               else
+                                       i="#"
+                               fi
+                       fi
+               fi
+
+               if [ -n "${1-}" ]; then
+                       printf "$1" "${b##refs/heads/}$w$i$r"
                else
-                       printf " (%s)" "${b##refs/heads/}$r"
+                       printf " (%s)" "${b##refs/heads/}$w$i$r"
                fi
        fi
 }
 
+# __gitcomp_1 requires 2 arguments
 __gitcomp_1 ()
 {
        local c IFS=' '$'\t'$'\n'
@@ -131,6 +159,8 @@ __gitcomp_1 ()
        done
 }
 
+# __gitcomp accepts 1, 2, 3, or 4 arguments
+# generates completion reply with compgen
 __gitcomp ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -143,22 +173,23 @@ __gitcomp ()
                ;;
        *)
                local IFS=$'\n'
-               COMPREPLY=($(compgen -P "$2" \
-                       -W "$(__gitcomp_1 "$1" "$4")" \
+               COMPREPLY=($(compgen -P "${2-}" \
+                       -W "$(__gitcomp_1 "${1-}" "${4-}")" \
                        -- "$cur"))
                ;;
        esac
 }
 
+# __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
 __git_heads ()
 {
-       local cmd i is_hash=y dir="$(__gitdir "$1")"
+       local cmd i is_hash=y dir="$(__gitdir "${1-}")"
        if [ -d "$dir" ]; then
                git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
                        refs/heads
                return
        fi
-       for i in $(git ls-remote "$1" 2>/dev/null); do
+       for i in $(git ls-remote "${1-}" 2>/dev/null); do
                case "$is_hash,$i" in
                y,*) is_hash=n ;;
                n,*^{}) is_hash=y ;;
@@ -168,15 +199,16 @@ __git_heads ()
        done
 }
 
+# __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
 __git_tags ()
 {
-       local cmd i is_hash=y dir="$(__gitdir "$1")"
+       local cmd i is_hash=y dir="$(__gitdir "${1-}")"
        if [ -d "$dir" ]; then
                git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
                        refs/tags
                return
        fi
-       for i in $(git ls-remote "$1" 2>/dev/null); do
+       for i in $(git ls-remote "${1-}" 2>/dev/null); do
                case "$is_hash,$i" in
                y,*) is_hash=n ;;
                n,*^{}) is_hash=y ;;
@@ -186,9 +218,10 @@ __git_tags ()
        done
 }
 
+# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
 __git_refs ()
 {
-       local i is_hash=y dir="$(__gitdir "$1")"
+       local i is_hash=y dir="$(__gitdir "${1-}")"
        local cur="${COMP_WORDS[COMP_CWORD]}" format refs
        if [ -d "$dir" ]; then
                case "$cur" in
@@ -218,6 +251,7 @@ __git_refs ()
        done
 }
 
+# __git_refs2 requires 1 argument (to pass to __git_refs)
 __git_refs2 ()
 {
        local i
@@ -226,6 +260,7 @@ __git_refs2 ()
        done
 }
 
+# __git_refs_remotes requires 1 argument (to pass to ls-remote)
 __git_refs_remotes ()
 {
        local cmd i is_hash=y
@@ -470,6 +505,7 @@ __git_aliases ()
        done
 }
 
+# __git_aliased_command requires 1 argument
 __git_aliased_command ()
 {
        local word cmdline=$(git --git-dir="$(__gitdir)" \
@@ -482,6 +518,7 @@ __git_aliased_command ()
        done
 }
 
+# __git_find_subcommand requires 1 argument
 __git_find_subcommand ()
 {
        local word subcommand c=1
@@ -563,7 +600,7 @@ _git_add ()
        --*)
                __gitcomp "
                        --interactive --refresh --patch --update --dry-run
-                       --ignore-errors
+                       --ignore-errors --intent-to-add
                        "
                return
        esac
@@ -628,7 +665,6 @@ _git_branch ()
        done
 
        case "${COMP_WORDS[COMP_CWORD]}" in
-       --*=*)  COMPREPLY=() ;;
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
@@ -759,23 +795,30 @@ _git_describe ()
        __gitcomp "$(__git_refs)"
 }
 
-_git_diff ()
-{
-       __git_has_doubledash && return
-
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       case "$cur" in
-       --*)
-               __gitcomp "--cached --stat --numstat --shortstat --summary
+__git_diff_common_options="--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=
-                       --find-copies-harder --pickaxe-all --pickaxe-regex
+                       --find-copies-harder
                        --text --ignore-space-at-eol --ignore-space-change
                        --ignore-all-space --exit-code --quiet --ext-diff
                        --no-ext-diff
                        --no-prefix --src-prefix= --dst-prefix=
+                       --inter-hunk-context=
+                       --patience
+                       --raw
+"
+
+_git_diff ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--cached --pickaxe-all --pickaxe-regex
                        --base --ours --theirs
+                       $__git_diff_common_options
                        "
                return
                ;;
@@ -823,6 +866,8 @@ _git_format_patch ()
                        --not --all
                        --cover-letter
                        --no-prefix --src-prefix= --dst-prefix=
+                       --inline --suffix= --ignore-if-in-upstream
+                       --subject-prefix=
                        "
                return
                ;;
@@ -930,6 +975,8 @@ _git_ls_tree ()
        __git_complete_file
 }
 
+__git_log_pretty_formats="oneline short medium full fuller email raw format:"
+
 _git_log ()
 {
        __git_has_doubledash && return
@@ -937,8 +984,7 @@ _git_log ()
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
-               __gitcomp "
-                       oneline short medium full fuller email raw
+               __gitcomp "$__git_log_pretty_formats
                        " "" "${cur##--pretty=}"
                return
                ;;
@@ -958,15 +1004,16 @@ _git_log ()
                        --relative-date --date=
                        --author= --committer= --grep=
                        --all-match
-                       --pretty= --name-status --name-only --raw
+                       --pretty=
                        --not --all
                        --left-right --cherry-pick
                        --graph
-                       --stat --numstat --shortstat
-                       --decorate --diff-filter=
-                       --color-words --walk-reflogs
+                       --decorate
+                       --walk-reflogs
                        --parents --children --full-history
                        --merge
+                       $__git_diff_common_options
+                       --pickaxe-all --pickaxe-regex
                        "
                return
                ;;
@@ -1367,7 +1414,7 @@ _git_config ()
 
 _git_remote ()
 {
-       local subcommands="add rm show prune update"
+       local subcommands="add rename rm show prune update"
        local subcommand="$(__git_find_subcommand "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
@@ -1375,7 +1422,7 @@ _git_remote ()
        fi
 
        case "$subcommand" in
-       rm|show|prune)
+       rename|rm|show|prune)
                __gitcomp "$(__git_remotes)"
                ;;
        update)
@@ -1403,7 +1450,7 @@ _git_reset ()
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
-               __gitcomp "--mixed --hard --soft"
+               __gitcomp "--merge --mixed --hard --soft"
                return
                ;;
        esac
@@ -1465,13 +1512,14 @@ _git_show ()
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
-               __gitcomp "
-                       oneline short medium full fuller email raw
+               __gitcomp "$__git_log_pretty_formats
                        " "" "${cur##--pretty=}"
                return
                ;;
        --*)
-               __gitcomp "--pretty="
+               __gitcomp "--pretty=
+                       $__git_diff_common_options
+                       "
                return
                ;;
        esac
@@ -1558,7 +1606,7 @@ _git_svn ()
                        --follow-parent --authors-file= --repack=
                        --no-metadata --use-svm-props --use-svnsync-props
                        --log-window-size= --no-checkout --quiet
-                       --repack-flags --user-log-author $remote_opts
+                       --repack-flags --user-log-author --localtime $remote_opts
                        "
                local init_opts="
                        --template= --shared= --trunk= --tags=
@@ -1672,7 +1720,6 @@ _git ()
 
        if [ -z "$command" ]; then
                case "${COMP_WORDS[COMP_CWORD]}" in
-               --*=*) COMPREPLY=() ;;
                --*)   __gitcomp "
                        --paginate
                        --no-pager
@@ -1736,6 +1783,7 @@ _git ()
        show)        _git_show ;;
        show-branch) _git_show_branch ;;
        stash)       _git_stash ;;
+       stage)       _git_add ;;
        submodule)   _git_submodule ;;
        svn)         _git_svn ;;
        tag)         _git_tag ;;
@@ -1763,13 +1811,16 @@ _gitk ()
        __git_complete_revlist
 }
 
-complete -o default -o nospace -F _git git
-complete -o default -o nospace -F _gitk gitk
+complete -o bashdefault -o default -o nospace -F _git git 2>/dev/null \
+       || complete -o default -o nospace -F _git git
+complete -o bashdefault -o default -o nospace -F _gitk gitk 2>/dev/null \
+       || complete -o default -o nospace -F _gitk gitk
 
 # 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 git.exe
+complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
+       || complete -o default -o nospace -F _git git.exe
 fi