Merge branch 'maint-1.8.5' into maint-1.9
[gitweb.git] / contrib / completion / git-prompt.sh
index 7b732d2aeba0e3bca3b42d28f2f8f5730a08ccee..e7ae736e4b6f7585e3d89960f8ff67455da81401 100644 (file)
@@ -207,7 +207,16 @@ __git_ps1_show_upstream ()
                        p=" u+${count#* }-${count%      *}" ;;
                esac
                if [[ -n "$count" && -n "$name" ]]; then
-                       p="$p $(git rev-parse --abbrev-ref "$upstream" 2>/dev/null)"
+                       __git_ps1_upstream_name=$(git rev-parse \
+                               --abbrev-ref "$upstream" 2>/dev/null)
+                       if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+                               p="$p \${__git_ps1_upstream_name}"
+                       else
+                               p="$p ${__git_ps1_upstream_name}"
+                               # not needed anymore; keep user's
+                               # environment clean
+                               unset __git_ps1_upstream_name
+                       fi
                fi
        fi
 
@@ -290,6 +299,43 @@ __git_ps1 ()
                ;;
        esac
 
+       # ps1_expanded:  This variable is set to 'yes' if the shell
+       # subjects the value of PS1 to parameter expansion:
+       #
+       #   * bash does unless the promptvars option is disabled
+       #   * zsh does not unless the PROMPT_SUBST option is set
+       #   * POSIX shells always do
+       #
+       # If the shell would expand the contents of PS1 when drawing
+       # the prompt, a raw ref name must not be included in PS1.
+       # This protects the user from arbitrary code execution via
+       # specially crafted ref names.  For example, a ref named
+       # 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the
+       # shell to execute 'sudo rm -rf /' when the prompt is drawn.
+       #
+       # Instead, the ref name should be placed in a separate global
+       # variable (in the __git_ps1_* namespace to avoid colliding
+       # with the user's environment) and that variable should be
+       # referenced from PS1.  For example:
+       #
+       #     __git_ps1_foo=$(do_something_to_get_ref_name)
+       #     PS1="...stuff...\${__git_ps1_foo}...stuff..."
+       #
+       # If the shell does not expand the contents of PS1, the raw
+       # ref name must be included in PS1.
+       #
+       # The value of this variable is only relevant when in pcmode.
+       #
+       # Assume that the shell follows the POSIX specification and
+       # expands PS1 unless determined otherwise.  (This is more
+       # likely to be correct if the user has a non-bash, non-zsh
+       # shell and safer than the alternative if the assumption is
+       # incorrect.)
+       #
+       local ps1_expanded=yes
+       [ -z "$ZSH_VERSION" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+       [ -z "$BASH_VERSION" ] || shopt -q promptvars || ps1_expanded=no
+
        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 \
@@ -438,8 +484,14 @@ __git_ps1 ()
                __git_ps1_colorize_gitstring
        fi
 
+       b=${b##refs/heads/}
+       if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+               __git_ps1_branch_name=$b
+               b="\${__git_ps1_branch_name}"
+       fi
+
        local f="$w$i$s$u"
-       local gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
+       local gitstring="$c$b${f:+$z$f}$r$p"
 
        if [ $pcmode = yes ]; then
                if [ "${__git_printf_supports_v-}" != yes ]; then