# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.
+#
+# If you would like __git_ps1 to do nothing in the case when the current
+# directory is set up to be ignored by git, then set
+# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
+# repository level by setting bash.hideIfPwdIgnored to "false".
# check whether printf supports -v
__git_printf_supports_v=
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
r="$c_clear$r"
}
-eread ()
+__git_eread ()
{
local f="$1"
shift
# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
__git_ps1 ()
{
+ # preserve exit status
+ local exit=$?
local pcmode=no
local detached=no
local ps1pc_start='\u@\h:\w '
ps1pc_start="$1"
ps1pc_end="$2"
printf_format="${3:-$printf_format}"
+ # set PS1 to a plain prompt so that we can
+ # simply return early if the prompt should not
+ # be decorated
+ PS1="$ps1pc_start$ps1pc_end"
;;
0|1) printf_format="${1:-$printf_format}"
;;
- *) return
+ *) return $exit
;;
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 \
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"
- fi
- return
+ return $exit
fi
local short_sha
local inside_gitdir="${repo_info##*$'\n'}"
local g="${repo_info%$'\n'*}"
+ if [ "true" = "$inside_worktree" ] &&
+ [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
+ [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
+ git check-ignore -q .
+ then
+ return $exit
+ fi
+
local r=""
local b=""
local step=""
local total=""
if [ -d "$g/rebase-merge" ]; then
- eread "$g/rebase-merge/head-name" b
- eread "$g/rebase-merge/msgnum" step
- eread "$g/rebase-merge/end" total
+ __git_eread "$g/rebase-merge/head-name" b
+ __git_eread "$g/rebase-merge/msgnum" step
+ __git_eread "$g/rebase-merge/end" total
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
else
fi
else
if [ -d "$g/rebase-apply" ]; then
- eread "$g/rebase-apply/next" step
- eread "$g/rebase-apply/last" total
+ __git_eread "$g/rebase-apply/next" step
+ __git_eread "$g/rebase-apply/last" total
if [ -f "$g/rebase-apply/rebasing" ]; then
- eread "$g/rebase-apply/head-name" b
+ __git_eread "$g/rebase-apply/head-name" b
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
local head=""
- if ! eread "$g/HEAD" head; then
- if [ $pcmode = yes ]; then
- PS1="$ps1pc_start$ps1pc_end"
- fi
- return
+ if ! __git_eread "$g/HEAD" head; then
+ return $exit
fi
# is it a symbolic ref?
b="${head#ref: }"
fi
fi
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
- [ -r "$g/refs/stash" ]; then
+ git rev-parse --verify --quiet refs/stash >/dev/null
+ then
s="$"
fi
__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
else
printf -- "$printf_format" "$gitstring"
fi
+
+ return $exit
}