Merge branch 'ft/doc-git-transport'
[gitweb.git] / contrib / completion / git-prompt.sh
index c2050b69bb9bf1830868b6b0c9ffdf53a52e1ef0..daed6a1d039cc8b2f5adb1d089e36ea7011e0536 100644 (file)
 #        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 #        ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
 #        the optional argument will be used as format string.
-#    3b) Alternatively, if you are using bash, __git_ps1 can be
-#        used for PROMPT_COMMAND with two parameters, <pre> and
-#        <post>, which are strings you would put in $PS1 before
-#        and after the status string generated by the git-prompt
-#        machinery.  e.g.
+#    3b) Alternatively, for a slighly faster prompt, if you are
+#        using bash, __git_ps1 can be used for PROMPT_COMMAND
+#        with two parameters, <pre> and <post>, which are strings
+#        you would put in $PS1 before and after the status string
+#        generated by the git-prompt machinery.  e.g.
 #        Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
 #        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
 #        will show username, at-sign, host, colon, cwd, then
@@ -311,8 +311,13 @@ __git_ps1 ()
                ;;
        esac
 
-       local g="$(git rev-parse --git-dir 2>/dev/null)"
-       if [ -z "$g" ]; then
+       local repo_info rev_parse_exit_code
+       repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
+               --is-bare-repository --is-inside-work-tree \
+               --short HEAD 2>/dev/null)"
+       rev_parse_exit_code="$?"
+
+       if [ -z "$repo_info" ]; then
                if [ $pcmode = yes ]; then
                        #In PC mode PS1 always needs to be set
                        PS1="$ps1pc_start$ps1pc_end"
@@ -320,6 +325,18 @@ __git_ps1 ()
                return
        fi
 
+       local short_sha
+       if [ "$rev_parse_exit_code" = "0" ]; then
+               short_sha="${repo_info##*$'\n'}"
+               repo_info="${repo_info%$'\n'*}"
+       fi
+       local inside_worktree="${repo_info##*$'\n'}"
+       repo_info="${repo_info%$'\n'*}"
+       local bare_repo="${repo_info##*$'\n'}"
+       repo_info="${repo_info%$'\n'*}"
+       local inside_gitdir="${repo_info##*$'\n'}"
+       local g="${repo_info%$'\n'*}"
+
        local r=""
        local b=""
        local step=""
@@ -384,8 +401,7 @@ __git_ps1 ()
                                        git describe --tags --exact-match HEAD ;;
                                esac 2>/dev/null)" ||
 
-                               b="$(git rev-parse --short HEAD 2>/dev/null)..." ||
-                               b="unknown"
+                               b="$short_sha..."
                                b="($b)"
                        fi
                fi
@@ -402,30 +418,31 @@ __git_ps1 ()
        local c=""
        local p=""
 
-       if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
-               if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
+       if [ "true" = "$inside_gitdir" ]; then
+               if [ "true" = "$bare_repo" ]; then
                        c="BARE:"
                else
                        b="GIT_DIR!"
                fi
-       elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+       elif [ "true" = "$inside_worktree" ]; then
                if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
                   [ "$(git config --bool bash.showDirtyState)" != "false" ]
                then
                        git diff --no-ext-diff --quiet --exit-code || w="*"
-                       if git rev-parse --quiet --verify HEAD >/dev/null; then
+                       if [ -n "$short_sha" ]; then
                                git diff-index --cached --quiet HEAD -- || i="+"
                        else
                                i="#"
                        fi
                fi
-               if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
-                       git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+               if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
+                  [ -r "$g/refs/stash" ]; then
+                       s="$"
                fi
 
                if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
                   [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
-                  [ -n "$(git ls-files --others --exclude-standard)" ]
+                  git ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null
                then
                        u="%${ZSH_VERSION+%}"
                fi
@@ -444,7 +461,11 @@ __git_ps1 ()
                else
                        gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
                fi
-               gitstring=$(printf -- "$printf_format" "$gitstring")
+               if [[ -n ${ZSH_VERSION-} ]]; then
+                       gitstring=$(printf -- "$printf_format" "$gitstring")
+               else
+                       printf -v gitstring -- "$printf_format" "$gitstring"
+               fi
                PS1="$ps1pc_start$gitstring$ps1pc_end"
        else
                # NO color option unless in PROMPT_COMMAND mode