From: Junio C Hamano Date: Wed, 1 Jul 2015 21:02:32 +0000 (-0700) Subject: Merge branch 'jc/prompt-document-ps1-state-separator' X-Git-Tag: v2.5.0-rc1~2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/d70bc3b97a4792ba99117ac6b0051ff367d78419?ds=inline;hp=-c Merge branch 'jc/prompt-document-ps1-state-separator' Docfix. * jc/prompt-document-ps1-state-separator: git-prompt.sh: document GIT_PS1_STATESEPARATOR --- d70bc3b97a4792ba99117ac6b0051ff367d78419 diff --combined contrib/completion/git-prompt.sh index f18aedc73b,be5467bb45..366f0bc1e9 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@@ -3,7 -3,7 +3,7 @@@ # Copyright (C) 2006,2007 Shawn O. Pearce # Distributed under the GNU General Public License, version 2.0. # -# This script allows you to see the current branch in your prompt. +# This script allows you to see repository status in your prompt. # # To enable: # @@@ -13,27 -13,23 +13,27 @@@ # 3a) Change your PS1 to call __git_ps1 as # command-substitution: # Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' -# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' +# ZSH: setopt PROMPT_SUBST ; 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,
 and
 -#        , which are strings you would put in $PS1 before
 -#        and after the status string generated by the git-prompt
 -#        machinery.  e.g.
 -#           PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
 -#        will show username, at-sign, host, colon, cwd, then
 -#        various status string, followed by dollar and SP, as
 -#        your prompt.
 +#    3b) Alternatively, for a slightly faster prompt, __git_ps1 can
 +#        be used for PROMPT_COMMAND in Bash or for precmd() in Zsh
 +#        with two parameters, 
 and , 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" "\\\$ "'
 +#          will show username, at-sign, host, colon, cwd, then
 +#          various status string, followed by dollar and SP, as
 +#          your prompt.
 +#        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
 +#          will show username, pipe, then various status string,
 +#          followed by colon, cwd, dollar and SP, as your prompt.
  #        Optionally, you can supply a third argument with a printf
  #        format string to finetune the output of the branch status
  #
 -# The argument to __git_ps1 will be displayed only if you are currently
 -# in a git repository.  The %s token will be the name of the current
 -# branch.
 +# The repository status will be displayed only if you are currently in a
 +# git repository. The %s token is the placeholder for the shown status.
 +#
 +# The prompt status always includes the current branch name.
  #
  # In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
  # unstaged (*) and staged (+) changes will be shown next to the branch
@@@ -60,12 -56,15 +60,16 @@@
  # of values:
  #
  #     verbose       show number of commits ahead/behind (+/-) upstream
 +#     name          if verbose, then also show the upstream abbrev name
  #     legacy        don't use the '--count' option available in recent
  #                   versions of git-rev-list
  #     git           always compare HEAD to @{upstream}
  #     svn           always compare HEAD to your SVN upstream
  #
+ # You can change the separator between the branch name and the above
+ # state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
+ # is SP.
+ #
  # By default, __git_ps1 will compare HEAD to your SVN upstream if it can
  # find one, or @{upstream} otherwise.  Once you have set
  # GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
@@@ -82,17 -81,31 +86,17 @@@
  #
  # If you would like a colored hint about the current dirty state, set
  # GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
 -# the colored output of "git status -sb".
 +# 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".
  
 -# __gitdir accepts 0 or 1 arguments (i.e., location)
 -# returns location of .git repo
 -__gitdir ()
 -{
 -	# Note: this function is duplicated in git-completion.bash
 -	# When updating it, make sure you update the other one to match.
 -	if [ -z "${1-}" ]; then
 -		if [ -n "${__git_dir-}" ]; then
 -			echo "$__git_dir"
 -		elif [ -n "${GIT_DIR-}" ]; then
 -			test -d "${GIT_DIR-}" || return 1
 -			echo "$GIT_DIR"
 -		elif [ -d .git ]; then
 -			echo .git
 -		else
 -			git rev-parse --git-dir 2>/dev/null
 -		fi
 -	elif [ -d "$1/.git" ]; then
 -		echo "$1/.git"
 -	else
 -		echo "$1"
 -	fi
 -}
 +# check whether printf supports -v
 +__git_printf_supports_v=
 +printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
  
  # stores the divergence from upstream in $p
  # used by GIT_PS1_SHOWUPSTREAM
@@@ -100,7 -113,7 +104,7 @@@ __git_ps1_show_upstream (
  {
  	local key value
  	local svn_remote svn_url_pattern count n
 -	local upstream=git legacy="" verbose=""
 +	local upstream=git legacy="" verbose="" name=""
  
  	svn_remote=()
  	# get some config options from git-config
@@@ -115,8 -128,8 +119,8 @@@
  			fi
  			;;
  		svn-remote.*.url)
 -			svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
 -			svn_url_pattern+="\\|$value"
 +			svn_remote[$((${#svn_remote[@]} + 1))]="$value"
 +			svn_url_pattern="$svn_url_pattern\\|$value"
  			upstream=svn+git # default upstream is SVN if available, else git
  			;;
  		esac
@@@ -128,7 -141,6 +132,7 @@@
  		git|svn) upstream="$option" ;;
  		verbose) verbose=1 ;;
  		legacy)  legacy=1  ;;
 +		name)    name=1 ;;
  		esac
  	done
  
@@@ -138,11 -150,10 +142,11 @@@
  	svn*)
  		# get the upstream from the "git-svn-id: ..." in a commit message
  		# (git-svn uses essentially the same procedure internally)
 -		local svn_upstream=($(git log --first-parent -1 \
 +		local -a svn_upstream
 +		svn_upstream=($(git log --first-parent -1 \
  					--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
  		if [[ 0 -ne ${#svn_upstream[@]} ]]; then
 -			svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
 +			svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
  			svn_upstream=${svn_upstream%@*}
  			local n_stop="${#svn_remote[@]}"
  			for ((n=1; n <= n_stop; n++)); do
@@@ -211,74 -222,10 +215,74 @@@
  		*)	    # diverged from upstream
  			p=" u+${count#*	}-${count%	*}" ;;
  		esac
 +		if [[ -n "$count" && -n "$name" ]]; then
 +			__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
 +
 +}
 +
 +# Helper function that is meant to be called from __git_ps1.  It
 +# injects color codes into the appropriate gitstring variables used
 +# to build a gitstring.
 +__git_ps1_colorize_gitstring ()
 +{
 +	if [[ -n ${ZSH_VERSION-} ]]; then
 +		local c_red='%F{red}'
 +		local c_green='%F{green}'
 +		local c_lblue='%F{blue}'
 +		local c_clear='%f'
 +	else
 +		# Using \[ and \] around colors is necessary to prevent
 +		# issues with command line editing/browsing/completion!
 +		local c_red='\[\e[31m\]'
 +		local c_green='\[\e[32m\]'
 +		local c_lblue='\[\e[1;34m\]'
 +		local c_clear='\[\e[0m\]'
  	fi
 +	local bad_color=$c_red
 +	local ok_color=$c_green
 +	local flags_color="$c_lblue"
  
 +	local branch_color=""
 +	if [ $detached = no ]; then
 +		branch_color="$ok_color"
 +	else
 +		branch_color="$bad_color"
 +	fi
 +	c="$branch_color$c"
 +
 +	z="$c_clear$z"
 +	if [ "$w" = "*" ]; then
 +		w="$bad_color$w"
 +	fi
 +	if [ -n "$i" ]; then
 +		i="$ok_color$i"
 +	fi
 +	if [ -n "$s" ]; then
 +		s="$flags_color$s"
 +	fi
 +	if [ -n "$u" ]; then
 +		u="$bad_color$u"
 +	fi
 +	r="$c_clear$r"
  }
  
 +__git_eread ()
 +{
 +	local f="$1"
 +	shift
 +	test -r "$f" && read "$@" <"$f"
 +}
  
  # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
  # when called from PS1 using command substitution
@@@ -293,8 -240,6 +297,8 @@@
  # 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 '
@@@ -306,132 -251,55 +310,132 @@@
  			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
  
 -	local g="$(__gitdir)"
 -	if [ -z "$g" ]; then
 -		if [ $pcmode = yes ]; then
 -			#In PC mode PS1 always needs to be set
 -			PS1="$ps1pc_start$ps1pc_end"
 +	# 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 \
 +		--short HEAD 2>/dev/null)"
 +	rev_parse_exit_code="$?"
 +
 +	if [ -z "$repo_info" ]; then
 +		return $exit
 +	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'*}"
 +
 +	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
 +		__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
 +			r="|REBASE-m"
  		fi
  	else
 -		local r=""
 -		local b=""
 -		local step=""
 -		local total=""
 -		if [ -d "$g/rebase-merge" ]; then
 -			b="$(cat "$g/rebase-merge/head-name")"
 -			step=$(cat "$g/rebase-merge/msgnum")
 -			total=$(cat "$g/rebase-merge/end")
 -			if [ -f "$g/rebase-merge/interactive" ]; then
 -				r="|REBASE-i"
 +		if [ -d "$g/rebase-apply" ]; then
 +			__git_eread "$g/rebase-apply/next" step
 +			__git_eread "$g/rebase-apply/last" total
 +			if [ -f "$g/rebase-apply/rebasing" ]; then
 +				__git_eread "$g/rebase-apply/head-name" b
 +				r="|REBASE"
 +			elif [ -f "$g/rebase-apply/applying" ]; then
 +				r="|AM"
  			else
 -				r="|REBASE-m"
 +				r="|AM/REBASE"
  			fi
 +		elif [ -f "$g/MERGE_HEAD" ]; then
 +			r="|MERGING"
 +		elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
 +			r="|CHERRY-PICKING"
 +		elif [ -f "$g/REVERT_HEAD" ]; then
 +			r="|REVERTING"
 +		elif [ -f "$g/BISECT_LOG" ]; then
 +			r="|BISECTING"
 +		fi
 +
 +		if [ -n "$b" ]; then
 +			:
 +		elif [ -h "$g/HEAD" ]; then
 +			# symlink symbolic ref
 +			b="$(git symbolic-ref HEAD 2>/dev/null)"
  		else
 -			if [ -d "$g/rebase-apply" ]; then
 -				step=$(cat "$g/rebase-apply/next")
 -				total=$(cat "$g/rebase-apply/last")
 -				if [ -f "$g/rebase-apply/rebasing" ]; then
 -					r="|REBASE"
 -				elif [ -f "$g/rebase-apply/applying" ]; then
 -					r="|AM"
 -				else
 -					r="|AM/REBASE"
 -				fi
 -			elif [ -f "$g/MERGE_HEAD" ]; then
 -				r="|MERGING"
 -			elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
 -				r="|CHERRY-PICKING"
 -			elif [ -f "$g/REVERT_HEAD" ]; then
 -				r="|REVERTING"
 -			elif [ -f "$g/BISECT_LOG" ]; then
 -				r="|BISECTING"
 +			local head=""
 +			if ! __git_eread "$g/HEAD" head; then
 +				return $exit
  			fi
 -
 -			b="$(git symbolic-ref HEAD 2>/dev/null)" || {
 +			# is it a symbolic ref?
 +			b="${head#ref: }"
 +			if [ "$head" = "$b" ]; then
  				detached=yes
  				b="$(
  				case "${GIT_PS1_DESCRIBE_STYLE-}" in
@@@ -445,84 -313,105 +449,84 @@@
  					git describe --tags --exact-match HEAD ;;
  				esac 2>/dev/null)" ||
  
 -				b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
 -				b="unknown"
 +				b="$short_sha..."
  				b="($b)"
 -			}
 +			fi
  		fi
 +	fi
  
 -		if [ -n "$step" ] && [ -n "$total" ]; then
 -			r="$r $step/$total"
 -		fi
 +	if [ -n "$step" ] && [ -n "$total" ]; then
 +		r="$r $step/$total"
 +	fi
  
 -		local w=""
 -		local i=""
 -		local s=""
 -		local u=""
 -		local c=""
 -		local p=""
 +	local w=""
 +	local i=""
 +	local s=""
 +	local u=""
 +	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
 -				c="BARE:"
 +	if [ "true" = "$inside_gitdir" ]; then
 +		if [ "true" = "$bare_repo" ]; then
 +			c="BARE:"
 +		else
 +			b="GIT_DIR!"
 +		fi
 +	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 [ -n "$short_sha" ]; then
 +				git diff-index --cached --quiet HEAD -- || i="+"
  			else
 -				b="GIT_DIR!"
 -			fi
 -		elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; 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
 -					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="$"
 +				i="#"
  			fi
 +		fi
 +		if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
 +		   git rev-parse --verify --quiet refs/stash >/dev/null
 +		then
 +			s="$"
 +		fi
  
 -			if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
 -			   [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
 -			   [ -n "$(git ls-files --others --exclude-standard)" ]
 -			then
 -				u="%${ZSH_VERSION+%}"
 -			fi
 +		if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
 +		   [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
 +		   git ls-files --others --exclude-standard --error-unmatch -- ':/*' >/dev/null 2>/dev/null
 +		then
 +			u="%${ZSH_VERSION+%}"
 +		fi
  
 -			if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
 -				__git_ps1_show_upstream
 -			fi
 +		if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
 +			__git_ps1_show_upstream
  		fi
 +	fi
  
 -		local z="${GIT_PS1_STATESEPARATOR-" "}"
 -		local f="$w$i$s$u"
 -		if [ $pcmode = yes ]; then
 -			local gitstring=
 -			if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
 -				local c_red='\e[31m'
 -				local c_green='\e[32m'
 -				local c_lblue='\e[1;34m'
 -				local c_clear='\e[0m'
 -				local bad_color=$c_red
 -				local ok_color=$c_green
 -				local branch_color="$c_clear"
 -				local flags_color="$c_lblue"
 -				local branchstring="$c${b##refs/heads/}"
 -
 -				if [ $detached = no ]; then
 -					branch_color="$ok_color"
 -				else
 -					branch_color="$bad_color"
 -				fi
 -
 -				# Setting gitstring directly with \[ and \] around colors
 -				# is necessary to prevent wrapping issues!
 -				gitstring="\[$branch_color\]$branchstring\[$c_clear\]"
 -
 -				if [ -n "$w$i$s$u$r$p" ]; then
 -					gitstring="$gitstring$z"
 -				fi
 -				if [ "$w" = "*" ]; then
 -					gitstring="$gitstring\[$bad_color\]$w"
 -				fi
 -				if [ -n "$i" ]; then
 -					gitstring="$gitstring\[$ok_color\]$i"
 -				fi
 -				if [ -n "$s" ]; then
 -					gitstring="$gitstring\[$flags_color\]$s"
 -				fi
 -				if [ -n "$u" ]; then
 -					gitstring="$gitstring\[$bad_color\]$u"
 -				fi
 -				gitstring="$gitstring\[$c_clear\]$r$p"
 -			else
 -				gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
 -			fi
 +	local z="${GIT_PS1_STATESEPARATOR-" "}"
 +
 +	# NO color option unless in PROMPT_COMMAND mode
 +	if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
 +		__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${f:+$z$f}$r$p"
 +
 +	if [ $pcmode = yes ]; then
 +		if [ "${__git_printf_supports_v-}" != yes ]; then
  			gitstring=$(printf -- "$printf_format" "$gitstring")
 -			PS1="$ps1pc_start$gitstring$ps1pc_end"
  		else
 -			# NO color option unless in PROMPT_COMMAND mode
 -			printf -- "$printf_format" "$c${b##refs/heads/}${f:+$z$f}$r$p"
 +			printf -v gitstring -- "$printf_format" "$gitstring"
  		fi
 +		PS1="$ps1pc_start$gitstring$ps1pc_end"
 +	else
 +		printf -- "$printf_format" "$gitstring"
  	fi
 +
 +	return $exit
  }