threads / patch / 30595

patch, 2 partscompletion: split into git-prompt.sh

Subject: [PATCH 0/2] completion: split into git-prompt.sh

## tl;dr

34 messages between May 22, 2012 and Nov 8, 2012. Diffs are folded; open one to read it.

replies: 33people: 12as markdown or json

Felipe Contreras· May 22, 2012, 20:46 UTC · lore
Hi,

This has been discussed before, but nobody has actually done it. Details in the relevant patch.

Felipe Contreras (2):
  completion: remove executable mode
  completion: split __git_ps1 into a separate script
 contrib/completion/git-completion.bash |  257 +---------------------------
 contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
 t/t9903-bash-prompt.sh                 |    2 +-
 3 files changed, 290 insertions(+), 256 deletions(-)
 mode change 100755 => 100644 contrib/completion/git-completion.bash
 create mode 100644 contrib/completion/git-prompt.sh
-- 
1.7.10.2
Felipe Contreras· May 22, 2012, 20:46 UTC · re: Felipe Contreras · lore

[PATCH 1/2] completion: remove executable mode

No reason to have it executable. Every way this script is intended to be used includes the 'source' command.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 0 files changed
 mode change 100755 => 100644 contrib/completion/git-completion.bash
Show changes to contrib/completion/git-completion.bash +0 −0
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
old mode 100755
new mode 100644
-- 
1.7.10.2
Felipe Contreras· May 22, 2012, 20:46 UTC · re: Felipe Contreras · lore

[PATCH 2/2] completion: split __git_ps1 into a separate script

bash-completion 1.90 shipped with support to load completions dynamically[1], which means the git completion script wouldn't be loaded until the user types 'git <tab>'--this creates a problem to people using __git_ps1(); that function won't be available when the shell is first created.

For now distributions have workarounded this issue by moving the git completion to the "compatdir"[2]; this of course is not ideal.

The solution, proposed by Kerrick Staley[3], is to split the git script in two; the part that deals with __git_ps1() in one (i.e. git-prompt.sh), and everything else in another (i.e. git-completion.bash).

Another benefit of this is that zsh user that are not interested in the bash completion can use it for their prompts, which has been tried before[4].

The only slight issue is that __gitdir() would be duplicated, but this is probably not a big deal.

So let's go ahead and move __git_ps1() to a new file.

While at this, I took the liberty to reformat the help text in the new file.

 [1] http://anonscm.debian.org/gitweb/?p=bash-completion/bash-completion.git;a=commitdiff;h=99c4f7f25f50a7cb2fce86055bddfe389effa559
 [2] http://projects.archlinux.org/svntogit/packages.git/commit/trunk?h=packages/git&id=974380fabb8f9f412990b17063bf578d98c44a82
 [3] http://mid.gmane.org/CANaWP3w9KDu57aHquRRYt8td_haSWTBKs7zUHy-xu0B61gmr9A@mail.gmail.com
 [4] http://mid.gmane.org/1303824288-15591-1-git-send-email-mstormo@gmail.com
Cc: Kerrick Staley <mail@kerrickstaley.com>
Cc: Marius Storm-Olsen <mstormo@gmail.com>
Cc: Ville Skyttä <ville.skytta@iki.fi>
Cc: Dan McGee <dan@archlinux.org>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/completion/git-completion.bash |  257 +---------------------------
 contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
 t/t9903-bash-prompt.sh                 |    2 +-
 3 files changed, 290 insertions(+), 256 deletions(-)
 create mode 100644 contrib/completion/git-prompt.sh
Show changes to 3 files +290 −256

contrib/completion/git-completion.bash, contrib/completion/git-prompt.sh, t/t9903-bash-prompt.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 44af124..59e4b5f 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -20,46 +20,8 @@
 #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
 #    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-completion.sh
-#
-#    3) Consider changing your PS1 to also show the current branch:
-#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
-#
-#       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.
-#
-#       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.
-#
-#       You can also see if currently something is stashed, by setting
-#       GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
-#       then a '$' will be shown next to the branch name.
-#
-#       If you would like to see if there're untracked files, then you can
-#       set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
-#       untracked files, then a '%' will be shown next to the branch name.
-#
-#       If you would like to see the difference between HEAD and its
-#       upstream, set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates
-#       you are behind, ">" indicates you are ahead, and "<>"
-#       indicates you have diverged.  You can further control
-#       behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
-#       list of values:
-#           verbose       show number of commits ahead/behind (+/-) upstream
-#           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
-#       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 setting the bash.showUpstream config
-#       variable.
-#
+#    3) Consider changing your PS1 to also show the current branch,
+#       see git-prompt.sh for details.
 
 if [[ -n ${ZSH_VERSION-} ]]; then
 	autoload -U +X bashcompinit && bashcompinit
@@ -92,221 +54,6 @@ __gitdir ()
 	fi
 }
 
-# stores the divergence from upstream in $p
-# used by GIT_PS1_SHOWUPSTREAM
-__git_ps1_show_upstream ()
-{
-	local key value
-	local svn_remote svn_url_pattern count n
-	local upstream=git legacy="" verbose=""
-
-	svn_remote=()
-	# get some config options from git-config
-	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
-	while read -r key value; do
-		case "$key" in
-		bash.showupstream)
-			GIT_PS1_SHOWUPSTREAM="$value"
-			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
-				p=""
-				return
-			fi
-			;;
-		svn-remote.*.url)
-			svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
-			svn_url_pattern+="\\|$value"
-			upstream=svn+git # default upstream is SVN if available, else git
-			;;
-		esac
-	done <<< "$output"
-
-	# parse configuration values
-	for option in ${GIT_PS1_SHOWUPSTREAM}; do
-		case "$option" in
-		git|svn) upstream="$option" ;;
-		verbose) verbose=1 ;;
-		legacy)  legacy=1  ;;
-		esac
-	done
-
-	# Find our upstream
-	case "$upstream" in
-	git)    upstream="@{upstream}" ;;
-	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 \
-					--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%@*}
-			local n_stop="${#svn_remote[@]}"
-			for ((n=1; n <= n_stop; n++)); do
-				svn_upstream=${svn_upstream#${svn_remote[$n]}}
-			done
-
-			if [[ -z "$svn_upstream" ]]; then
-				# default branch name for checkouts with no layout:
-				upstream=${GIT_SVN_ID:-git-svn}
-			else
-				upstream=${svn_upstream#/}
-			fi
-		elif [[ "svn+git" = "$upstream" ]]; then
-			upstream="@{upstream}"
-		fi
-		;;
-	esac
-
-	# Find how many commits we are ahead/behind our upstream
-	if [[ -z "$legacy" ]]; then
-		count="$(git rev-list --count --left-right \
-				"$upstream"...HEAD 2>/dev/null)"
-	else
-		# produce equivalent output to --count for older versions of git
-		local commits
-		if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
-		then
-			local commit behind=0 ahead=0
-			for commit in $commits
-			do
-				case "$commit" in
-				"<"*) ((behind++)) ;;
-				*)    ((ahead++))  ;;
-				esac
-			done
-			count="$behind	$ahead"
-		else
-			count=""
-		fi
-	fi
-
-	# calculate the result
-	if [[ -z "$verbose" ]]; then
-		case "$count" in
-		"") # no upstream
-			p="" ;;
-		"0	0") # equal to upstream
-			p="=" ;;
-		"0	"*) # ahead of upstream
-			p=">" ;;
-		*"	0") # behind upstream
-			p="<" ;;
-		*)	    # diverged from upstream
-			p="<>" ;;
-		esac
-	else
-		case "$count" in
-		"") # no upstream
-			p="" ;;
-		"0	0") # equal to upstream
-			p=" u=" ;;
-		"0	"*) # ahead of upstream
-			p=" u+${count#0	}" ;;
-		*"	0") # behind upstream
-			p=" u-${count%	0}" ;;
-		*)	    # diverged from upstream
-			p=" u+${count#*	}-${count%	*}" ;;
-		esac
-	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="$(__gitdir)"
-	if [ -n "$g" ]; then
-		local r=""
-		local b=""
-		if [ -f "$g/rebase-merge/interactive" ]; then
-			r="|REBASE-i"
-			b="$(cat "$g/rebase-merge/head-name")"
-		elif [ -d "$g/rebase-merge" ]; then
-			r="|REBASE-m"
-			b="$(cat "$g/rebase-merge/head-name")"
-		else
-			if [ -d "$g/rebase-apply" ]; then
-				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/BISECT_LOG" ]; then
-				r="|BISECTING"
-			fi
-
-			b="$(git symbolic-ref HEAD 2>/dev/null)" || {
-
-				b="$(
-				case "${GIT_PS1_DESCRIBE_STYLE-}" in
-				(contains)
-					git describe --contains HEAD ;;
-				(branch)
-					git describe --contains --all HEAD ;;
-				(describe)
-					git describe HEAD ;;
-				(* | default)
-					git describe --tags --exact-match HEAD ;;
-				esac 2>/dev/null)" ||
-
-				b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
-				b="unknown"
-				b="($b)"
-			}
-		fi
-
-		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:"
-			else
-				b="GIT_DIR!"
-			fi
-		elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
-			if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
-				if [ "$(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
-			fi
-			if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
-				git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
-			fi
-
-			if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
-				if [ -n "$(git ls-files --others --exclude-standard)" ]; then
-					u="%"
-				fi
-			fi
-
-			if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
-				__git_ps1_show_upstream
-			fi
-		fi
-
-		local f="$w$i$s$u"
-		printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
-	fi
-}
-
 __gitcomp_1 ()
 {
 	local c IFS=$' \t\n'
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
new file mode 100644
index 0000000..8e2e9f3
--- /dev/null
+++ b/contrib/completion/git-prompt.sh
@@ -0,0 +1,287 @@
+# bash/zsh git prompt support
+#
+# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
+# Distributed under the GNU General Public License, version 2.0.
+#
+# This script allows you to see the current branch in your prompt.
+#
+# To enable:
+#
+#    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
+#    2) Add the following line to your .bashrc/.zshrc:
+#        source ~/.git-prompt.sh
+#    3) Change your PS1 to also show the current branch:
+#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+#
+# 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.
+#
+# 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.
+#
+# You can also see if currently something is stashed, by setting
+# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+# then a '$' will be shown next to the branch name.
+#
+# If you would like to see if there're untracked files, then you can set
+# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
+# files, then a '%' will be shown next to the branch name.
+#
+# If you would like to see the difference between HEAD and its upstream,
+# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
+# indicates you are ahead, and "<>" indicates you have diverged.  You
+# can further control behaviour by setting GIT_PS1_SHOWUPSTREAM to a
+# space-separated list of values:
+#
+#     verbose       show number of commits ahead/behind (+/-) upstream
+#     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
+#
+# 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
+# setting the bash.showUpstream config variable.
+
+# __gitdir accepts 0 or 1 arguments (i.e., location)
+# returns location of .git repo
+__gitdir ()
+{
+	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
+}
+
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+	local key value
+	local svn_remote svn_url_pattern count n
+	local upstream=git legacy="" verbose=""
+
+	svn_remote=()
+	# get some config options from git-config
+	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+	while read -r key value; do
+		case "$key" in
+		bash.showupstream)
+			GIT_PS1_SHOWUPSTREAM="$value"
+			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+				p=""
+				return
+			fi
+			;;
+		svn-remote.*.url)
+			svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+			svn_url_pattern+="\\|$value"
+			upstream=svn+git # default upstream is SVN if available, else git
+			;;
+		esac
+	done <<< "$output"
+
+	# parse configuration values
+	for option in ${GIT_PS1_SHOWUPSTREAM}; do
+		case "$option" in
+		git|svn) upstream="$option" ;;
+		verbose) verbose=1 ;;
+		legacy)  legacy=1  ;;
+		esac
+	done
+
+	# Find our upstream
+	case "$upstream" in
+	git)    upstream="@{upstream}" ;;
+	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 \
+					--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%@*}
+			local n_stop="${#svn_remote[@]}"
+			for ((n=1; n <= n_stop; n++)); do
+				svn_upstream=${svn_upstream#${svn_remote[$n]}}
+			done
+
+			if [[ -z "$svn_upstream" ]]; then
+				# default branch name for checkouts with no layout:
+				upstream=${GIT_SVN_ID:-git-svn}
+			else
+				upstream=${svn_upstream#/}
+			fi
+		elif [[ "svn+git" = "$upstream" ]]; then
+			upstream="@{upstream}"
+		fi
+		;;
+	esac
+
+	# Find how many commits we are ahead/behind our upstream
+	if [[ -z "$legacy" ]]; then
+		count="$(git rev-list --count --left-right \
+				"$upstream"...HEAD 2>/dev/null)"
+	else
+		# produce equivalent output to --count for older versions of git
+		local commits
+		if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+		then
+			local commit behind=0 ahead=0
+			for commit in $commits
+			do
+				case "$commit" in
+				"<"*) ((behind++)) ;;
+				*)    ((ahead++))  ;;
+				esac
+			done
+			count="$behind	$ahead"
+		else
+			count=""
+		fi
+	fi
+
+	# calculate the result
+	if [[ -z "$verbose" ]]; then
+		case "$count" in
+		"") # no upstream
+			p="" ;;
+		"0	0") # equal to upstream
+			p="=" ;;
+		"0	"*) # ahead of upstream
+			p=">" ;;
+		*"	0") # behind upstream
+			p="<" ;;
+		*)	    # diverged from upstream
+			p="<>" ;;
+		esac
+	else
+		case "$count" in
+		"") # no upstream
+			p="" ;;
+		"0	0") # equal to upstream
+			p=" u=" ;;
+		"0	"*) # ahead of upstream
+			p=" u+${count#0	}" ;;
+		*"	0") # behind upstream
+			p=" u-${count%	0}" ;;
+		*)	    # diverged from upstream
+			p=" u+${count#*	}-${count%	*}" ;;
+		esac
+	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="$(__gitdir)"
+	if [ -n "$g" ]; then
+		local r=""
+		local b=""
+		if [ -f "$g/rebase-merge/interactive" ]; then
+			r="|REBASE-i"
+			b="$(cat "$g/rebase-merge/head-name")"
+		elif [ -d "$g/rebase-merge" ]; then
+			r="|REBASE-m"
+			b="$(cat "$g/rebase-merge/head-name")"
+		else
+			if [ -d "$g/rebase-apply" ]; then
+				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/BISECT_LOG" ]; then
+				r="|BISECTING"
+			fi
+
+			b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+				b="$(
+				case "${GIT_PS1_DESCRIBE_STYLE-}" in
+				(contains)
+					git describe --contains HEAD ;;
+				(branch)
+					git describe --contains --all HEAD ;;
+				(describe)
+					git describe HEAD ;;
+				(* | default)
+					git describe --tags --exact-match HEAD ;;
+				esac 2>/dev/null)" ||
+
+				b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+				b="unknown"
+				b="($b)"
+			}
+		fi
+
+		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:"
+			else
+				b="GIT_DIR!"
+			fi
+		elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+			if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
+				if [ "$(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
+			fi
+			if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
+				git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+			fi
+
+			if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
+				if [ -n "$(git ls-files --others --exclude-standard)" ]; then
+					u="%"
+				fi
+			fi
+
+			if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+				__git_ps1_show_upstream
+			fi
+		fi
+
+		local f="$w$i$s$u"
+		printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
+	fi
+}
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index 96468ce..f17c1f8 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -7,7 +7,7 @@ test_description='test git-specific bash prompt functions'
 
 . ./lib-bash.sh
 
-. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
+. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
 
 actual="$TRASH_DIRECTORY/actual"
 
-- 
1.7.10.2
Zbigniew Jędrzejewski-Szmek· May 22, 2012, 21:07 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On 05/22/2012 10:46 PM, Felipe Contreras wrote:
Show 5 quoted lines
>  contrib/completion/git-completion.bash |  257 +---------------------------
>  contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
>  t/t9903-bash-prompt.sh                 |    2 +-
>  3 files changed, 290 insertions(+), 256 deletions(-)
>  create mode 100644 contrib/completion/git-prompt.sh

Hi, since git-prompt is not completion related anymore, should a different directory be used?

Zbyszek
Ted Pavlic· May 22, 2012, 22:29 UTC · re: Zbigniew Jędrzejewski-Szmek · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

>>  create mode 100644 contrib/completion/git-prompt.sh
> Hi,
> since git-prompt is not completion related anymore, should a different
> directory be used?

Making it even more likely that the __gitdir in one will someday not match the __gitdir in another...

Maybe __gitdir should live inside git-prompt and git-completion would include git-prompt. That would make everything backward compatible too. And that way there's a good answer to why git-prompt lives inside the completion directory.

-- 
Ted Pavlic <ted@tedpavlic.com>
Felipe Contreras· May 23, 2012, 11:56 UTC · re: Ted Pavlic · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Wed, May 23, 2012 at 12:29 AM, Ted Pavlic <ted@tedpavlic.com> wrote:
Show 7 quoted lines
>>>  create mode 100644 contrib/completion/git-prompt.sh
>> Hi,
>> since git-prompt is not completion related anymore, should a different
>> directory be used?
>
> Making it even more likely that the __gitdir in one will someday not
> match the __gitdir in another...

Which is not a big deal IMO. The "bad" __gitdir() won't get worst than the current one.

> Maybe __gitdir should live inside git-prompt and git-completion would
> include git-prompt. That would make everything backward compatible
> too. And that way there's a good answer to why git-prompt lives inside
> the completion directory.

That's not bad, but still needs people to copy multiple scripts, and edit. I prefer to have a 'git dir' or something.

-- 
Felipe Contreras
Felipe Contreras· May 23, 2012, 11:59 UTC · re: Zbigniew Jędrzejewski-Szmek · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Tue, May 22, 2012 at 11:07 PM, Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> wrote:

Show 6 quoted lines
> On 05/22/2012 10:46 PM, Felipe Contreras wrote:
>>  contrib/completion/git-completion.bash |  257 +---------------------------
>>  contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
>>  t/t9903-bash-prompt.sh                 |    2 +-
>>  3 files changed, 290 insertions(+), 256 deletions(-)
>>  create mode 100644 contrib/completion/git-prompt.sh
> since git-prompt is not completion related anymore, should a different
> directory be used?

That's a good point. I personally wouldn't worry too much about this until there's a real issue. If we were to fix this, I would rather have a 'shell' sub-directory and move everything there; I think have a sub-directory for 'completion' and another for 'prompt' would be overkill.

Unfortunately this would mean packagers need to update.
Cheers.
-- 
Felipe Contreras
Junio C Hamano· May 23, 2012, 14:54 UTC · re: Zbigniew Jędrzejewski-Szmek · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Zbigniew Jędrzejewski-Szmek  <zbyszek@in.waw.pl> writes:
Show 9 quoted lines
> On 05/22/2012 10:46 PM, Felipe Contreras wrote:
>>  contrib/completion/git-completion.bash |  257 +---------------------------
>>  contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
>>  t/t9903-bash-prompt.sh                 |    2 +-
>>  3 files changed, 290 insertions(+), 256 deletions(-)
>>  create mode 100644 contrib/completion/git-prompt.sh
> Hi,
> since git-prompt is not completion related anymore, should a different
> directory be used?

I am not sure if that is worth it. These two share/duplicate some shell functions and we may end up refactoring them (a way to do so may be to dot-source git-prompt from git-completion and drop duplicated definitions from the latter), for example.

Felipe Contreras· May 23, 2012, 15:40 UTC · re: Junio C Hamano · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Hi,
On Wed, May 23, 2012 at 4:54 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 16 quoted lines
> Zbigniew Jędrzejewski-Szmek  <zbyszek@in.waw.pl> writes:
>
>> On 05/22/2012 10:46 PM, Felipe Contreras wrote:
>>>  contrib/completion/git-completion.bash |  257 +---------------------------
>>>  contrib/completion/git-prompt.sh       |  287 ++++++++++++++++++++++++++++++++
>>>  t/t9903-bash-prompt.sh                 |    2 +-
>>>  3 files changed, 290 insertions(+), 256 deletions(-)
>>>  create mode 100644 contrib/completion/git-prompt.sh
>> Hi,
>> since git-prompt is not completion related anymore, should a different
>> directory be used?
>
> I am not sure if that is worth it.  These two share/duplicate some shell
> functions and we may end up refactoring them (a way to do so may be to
> dot-source git-prompt from git-completion and drop duplicated definitions
> from the latter), for example.
And how do you propose to update the install documentation?

# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). # 2) Add the following line to your .bashrc/.zshrc: # source ~/.git-completion.sh # # 3) Consider changing your PS1 to also show the current branch:

1) Copy the file (e.g. ~/.git-completion.sh)
2) Copy the other file (.e.g ~/.git-prompt.sh)
3) Edit the original file (~/.git-completion.sh), modify the 'source'
command to use the other file (~/.git-prompt.sh)
And if the user doesn't care about prompt this certainly looks like overkill.

What do we gain by this incredible user annoyance? Less maintenance burden of __gitdir() which barely changes anyway?

What about 'git dir' or 'git info dir' (this could be used by other scripts to get information about various git commands, for completion, documentation, what not)?

Cheers.
-- 
Felipe Contreras
Junio C Hamano· May 23, 2012, 16:30 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 14 quoted lines
> And how do you propose to update the install documentation?
>
> #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
> #    2) Add the following line to your .bashrc/.zshrc:
> #        source ~/.git-completion.sh
> #
> #    3) Consider changing your PS1 to also show the current branch:
>
> 1) Copy the file (e.g. ~/.git-completion.sh)
> 2) Copy the other file (.e.g ~/.git-prompt.sh)
> 3) Edit the original file (~/.git-completion.sh), modify the 'source'
> command to use the other file (~/.git-prompt.sh)
>
> And if the user doesn't care about prompt this certainly looks like overkill.
Agreed--the above would not fly.
> What do we gain by this incredible user annoyance? Less maintenance
> burden of __gitdir() which barely changes anyway?

If it lived in two separate projects, the pros-and-cons might be differnt because there will be cost for coordinating changes between the projects, but I do not think "barely changes" is a good rationale to keep duplicates in this case, as we know both files come from the same project, and there is no release engineering cost to coordiate changes. The only price we pay by not removing the duplicates at the source level is the risk of two drifting apart without anybody noticing, and that particular risk becomes the more likely the less often the function changes. In other words, "barely changes" is an argument _for_ removing duplicates.

Splitting the definition of whatever is duplicated out to a separate file, having contrib/completion/Makefile insert it at an appropriate place in both scripts at the build time, and driving that machinery from the Makefile at the top-level would be one possible way forward. For people who download and install from the source, the "install insn" could also be added to the generated file to avoid confusion (and for people who just get the script(s) from their distro, the packagers would do that for them).

You may think of a better solution to remove duplicates, of course, so I am not married to the "have Makefile do it" approach and am open to suggestions.

Ted Pavlic· May 23, 2012, 17:03 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Show 11 quoted lines
>> I am not sure if that is worth it.  These two share/duplicate some shell
>> functions and we may end up refactoring them (a way to do so may be to
>> dot-source git-prompt from git-completion and drop duplicated definitions
>> from the latter), for example.
>
> And how do you propose to update the install documentation?
>
> 1) Copy the file (e.g. ~/.git-completion.sh)
> 2) Copy the other file (.e.g ~/.git-prompt.sh)
> 3) Edit the original file (~/.git-completion.sh), modify the 'source'
> command to use the other file (~/.git-prompt.sh)

The third step doesn't seem necessary if .git-completion sources git-prompt when it's available (and otherwise ignores it gracefully). Then anyone who cares about the prompt just makes sure that git-prompt is available.

-- 
Ted Pavlic <ted@tedpavlic.com>
Felipe Contreras· May 23, 2012, 20:50 UTC · re: Ted Pavlic · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Wed, May 23, 2012 at 7:03 PM, Ted Pavlic <ted@tedpavlic.com> wrote:
Show 16 quoted lines
>>> I am not sure if that is worth it.  These two share/duplicate some shell
>>> functions and we may end up refactoring them (a way to do so may be to
>>> dot-source git-prompt from git-completion and drop duplicated definitions
>>> from the latter), for example.
>>
>> And how do you propose to update the install documentation?
>>
>> 1) Copy the file (e.g. ~/.git-completion.sh)
>> 2) Copy the other file (.e.g ~/.git-prompt.sh)
>> 3) Edit the original file (~/.git-completion.sh), modify the 'source'
>> command to use the other file (~/.git-prompt.sh)
>
> The third step doesn't seem necessary if .git-completion sources
> git-prompt when it's available (and otherwise ignores it gracefully).
> Then anyone who cares about the prompt just makes sure that git-prompt
> is available.
And then anything that uses __gitdir() would fail.

And how would you figure if it's available, and where it is available? What if git-completion.bash is distributed on /usr/share/bash-completion/completions/git? Where would you put git-prompt.sh so it can be found *and* you would not require modifications? And what if I want to put the latest version on ~/.git-completion.sh (as the script actually suggests).

There's no way git-prompt.sh can be sourced without modifications to the script, unless you expect it would always be named '.git-prompt.sh' and would be on the same directory, which many distributions would frown upon.

-- 
Felipe Contreras
Ted Pavlic· May 23, 2012, 21:55 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

> There's no way git-prompt.sh can be sourced without modifications to
> the script, unless you expect it would always be named
> '.git-prompt.sh' and would be on the same directory, which many
> distributions would frown upon.

So, again, seems like a good argument for building a git-gitdir into git proper. Maybe there are other utilities that could make use of it as well...

-- 
Ted Pavlic <ted@tedpavlic.com>
SZEDER Gábor· May 24, 2012, 20:35 UTC · re: Ted Pavlic · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Hi,
On Wed, May 23, 2012 at 05:55:13PM -0400, Ted Pavlic wrote:
Show 8 quoted lines
> > There's no way git-prompt.sh can be sourced without modifications to
> > the script, unless you expect it would always be named
> > '.git-prompt.sh' and would be on the same directory, which many
> > distributions would frown upon.
> 
> So, again, seems like a good argument for building a git-gitdir into git
> proper. Maybe there are other utilities that could make use of it as
> well...

You mean a real git command, which does the same as __gitdir()? I don't like that, because it will always require 2 fork()s and an exec() and would be slow on Windows.

Best, Gábor

SZEDER Gábor· May 24, 2012, 20:49 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Wed, May 23, 2012 at 05:40:46PM +0200, Felipe Contreras wrote:
> What do we gain by this incredible user annoyance? Less maintenance
> burden of __gitdir() which barely changes anyway?

I happen to have a topic in the works which changes __gitdir() and adds some helper functions to it, so the diffstat of all __gitdir()-related changes is this:

 1 file changed, 71 insertions(+), 6 deletions(-)
Gábor
Ted Pavlic· May 22, 2012, 22:27 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

> The solution, proposed by Kerrick Staley[3], is to split the git script
> in two; the part that deals with __git_ps1() in one (i.e.
> git-prompt.sh), and everything else in another (i.e.
> git-completion.bash).

Seems like this solution has popped up on lots of forums for about every Linux distribution around the time the new bash completion was introduced. I'm not sure Kerric Staley deserves sole attribution (sorry Kerrick; I mean no offense).

Moreover, every time the subject of splitting __gitdir out comes up, a side discussion about all of the complications that could cause comes up... and people give up and hope that the folks upstream (i.e., here) will come up with a better solution.

If it was so simple to just split __gitdir out, I think it would have already been done.

> The only slight issue is that __gitdir() would be duplicated, but this
> is probably not a big deal.

That seems ugly. I know that splitting __gitdir out is also ugly, but I know that there are going to be a lot more people who use git completion than git_ps1. Consequently, in a duplicated __gitdir scneario, I worry that __gitdir will receive more attention and may relatively quickly diverge in implementation if not very careful in approving patches. Moreover, a __gitdir of the future may not be atomic and will pick up side effects and become impossible to manage in two places.

So maybe a split out "git-gitdir.sh" that both files include would be "better." Either that or the functionality of "__gitdir" gets pulled into git itself. (perhaps a git-gitdir added to the main git distribution)

> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
As the patch is from you, there's no need to sign off on it too.
--Ted
-- 
Ted Pavlic <ted@tedpavlic.com>
Felipe Contreras· May 23, 2012, 11:53 UTC · re: Ted Pavlic · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Wed, May 23, 2012 at 12:27 AM, Ted Pavlic <ted@tedpavlic.com> wrote:
Show 9 quoted lines
>> The solution, proposed by Kerrick Staley[3], is to split the git script
>> in two; the part that deals with __git_ps1() in one (i.e.
>> git-prompt.sh), and everything else in another (i.e.
>> git-completion.bash).
>
> Seems like this solution has popped up on lots of forums for about
> every Linux distribution around the time the new bash completion was
> introduced. I'm not sure Kerric Staley deserves sole attribution
> (sorry Kerrick; I mean no offense).

I didn't attribute it to him, I merely said he proposed it, which he did, I did not make any statement about him being the sole author of this idea.

I don't recall this solution for this problem being proposed in this mailing list by anybody else though. And I don't think it's relevant.

> Moreover, every time the subject of splitting __gitdir out comes up, a
> side discussion about all of the complications that could cause comes
> up... and people give up and hope that the folks upstream (i.e., here)
> will come up with a better solution.

This is the reply Kerrick got to his suggestion from Jeff King: http://article.gmane.org/gmane.comp.version-control.git/194230

I also agreed, and so did Jonathan Nieder: http://article.gmane.org/gmane.comp.version-control.git/194950

So I don't see what you mean by those side "discussions" I recall Junio objecting to this, but the split was meant to solve another issue (zsh).

Show 14 quoted lines
> If it was so simple to just split __gitdir out, I think it would have
> already been done.
>
>> The only slight issue is that __gitdir() would be duplicated, but this
>> is probably not a big deal.
>
> That seems ugly. I know that splitting __gitdir out is also ugly, but
> I know that there are going to be a lot more people who use git
> completion than git_ps1. Consequently, in a duplicated __gitdir
> scneario, I worry that __gitdir will receive more attention and may
> relatively quickly diverge in implementation if not very careful in
> approving patches. Moreover, a __gitdir of the future may not be
> atomic and will pick up side effects and become impossible to manage
> in two places.

Perhaps, but it wouldn't work worst than the current __gitdir(). And I haven't heard any better suggestions yet.

> So maybe a split out "git-gitdir.sh" that both files include would be
> "better." Either that or the functionality of "__gitdir" gets pulled
> into git itself. (perhaps a git-gitdir added to the main git
> distribution)

I like the idea of 'git gitdir' (or 'git dir'), and I dislike the idea of 'git-gitdir.sh'; people would need to copy one extra file, and probably edit multiple files.

>> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
>
> As the patch is from you, there's no need to sign off on it too.

Yes I do, according to Linux guidelines[1], and that's what I've been always doing in the git mailing list.

Anyway, before going straight to a negative attitude, why don't we wait for more comments before making any conclusions?

Cheers.
[1] http://www.kernel.org/doc/Documentation/SubmittingPatches
-- 
Felipe Contreras
Junio C Hamano· May 23, 2012, 14:59 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 15 quoted lines
> On Wed, May 23, 2012 at 12:27 AM, Ted Pavlic <ted@tedpavlic.com> wrote:
> ...
>> Moreover, every time the subject of splitting __gitdir out comes up, a
>> side discussion about all of the complications that could cause comes
>> up... and people give up and hope that the folks upstream (i.e., here)
>> will come up with a better solution.
>
> This is the reply Kerrick got to his suggestion from Jeff King:
> http://article.gmane.org/gmane.comp.version-control.git/194230
>
> I also agreed, and so did Jonathan Nieder:
> http://article.gmane.org/gmane.comp.version-control.git/194950
>
> So I don't see what you mean by those side "discussions" I recall
> Junio objecting to this, but...

A comment just on this part to avoid misunderstanding. I do not recall objecting to the above two articles, and after reading them again, I am happy with the direction. The message from me in the thread they are in was merely me asking clarifications.

SZEDER Gábor· May 24, 2012, 20:47 UTC · re: Felipe Contreras · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Hi,
On Tue, May 22, 2012 at 10:46:40PM +0200, Felipe Contreras wrote:
> bash-completion 1.90 shipped 

That's still beta, right? (or the bash-completion website is out of date...)

Show 13 quoted lines
> with support to load completions
> dynamically[1], which means the git completion script wouldn't be loaded
> until the user types 'git <tab>'--this creates a problem to people using
> __git_ps1(); that function won't be available when the shell is first
> created.
> 
> For now distributions have workarounded this issue by moving the git
> completion to the "compatdir"[2]; this of course is not ideal.
> 
> The solution, proposed by Kerrick Staley[3], is to split the git script
> in two; the part that deals with __git_ps1() in one (i.e.
> git-prompt.sh), and everything else in another (i.e.
> git-completion.bash).

This breaks existing setups, where the user installs git-completion.bash with 'make install', or where the user sources git-completion.bash directly from the repository.

Best, Gábor

Ville Skyttä· May 25, 2012, 17:51 UTC · re: SZEDER Gábor · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On 2012-05-24 23:47, SZEDER Gábor wrote:
Show 6 quoted lines
> 
> On Tue, May 22, 2012 at 10:46:40PM +0200, Felipe Contreras wrote:
>> bash-completion 1.90 shipped 
> 
> That's still beta, right?  (or the bash-completion website is out of
> date...)

1.99 has been out since January, and the website has also mentioned it since then. 1.99 is a beta or a release candidate if you prefer, but personally I believe it's very close to 2.0 at least in terms of things being discussed in this thread.

Jonathan Nieder· Oct 25, 2012, 00:51 UTC · re: Felipe Contreras · lore

Where should git-prompt.sh be installed?

Hi,

In olden days the admin would copy contrib/completion/git-completion.sh to

        /etc/bash_completion.d/git

and mortals could source /etc/bash_completion or /etc/bash_completion.d/git in their ~/.bashrc (possibly shared among multiple machines) so that the bash completion and __git_ps1 helpers could work.

With Git 1.7.12 __git_ps1 has been split into a separate file, to help users who only want __git_ps1 to avoid the overhead of loading the entire completion script (and allow the completion script to be loaded by bash-completion magic on the fly!). Now the sysadmin should copy contrib/completion/git-completion.sh to

	/usr/share/bash-completion/completions/git
and contrib/completion/git-prompt.sh to
	/usr/share/git-core/contrib/?? (somewhere?)

Mortals source /etc/bash_completion in their ~/.bashrc (possibly shared among multiple machines) and expect bash completion to work. For __git_ps1, users should source that ?? path.

Questions:
 1) what path is appropriate for ?? above?
 2) is this documented anywhere?
Possible answers:
 1) Fedora uses /etc/profile.d/git-prompt.sh.  Gentoo uses
    /usr/share/bash-completion/git-prompt.  Maybe others use
    some other path.
 2) The scripts themselves suggest copying to ~/.git-completion.sh
    and ~/.git-prompt.sh.
Proposal:
  1) /usr/lib/git-core/git-sh-prompt
  2) git-sh-prompt(1)
Sensible?

Thanks, Jonathan

Drew Northup· Oct 25, 2012, 01:59 UTC · re: Jonathan Nieder · lore

Re: Where should git-prompt.sh be installed?

On Wed, Oct 24, 2012 at 8:51 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:
Show 33 quoted lines
> Now the sysadmin should copy
> contrib/completion/git-completion.sh to
>
>         /usr/share/bash-completion/completions/git
>
> and contrib/completion/git-prompt.sh to
>
>         /usr/share/git-core/contrib/?? (somewhere?)
>
> Mortals source /etc/bash_completion in their ~/.bashrc (possibly
> shared among multiple machines) and expect bash completion to work.
> For __git_ps1, users should source that ?? path.
>
> Questions:
>
>  1) what path is appropriate for ?? above?
>  2) is this documented anywhere?
>
> Possible answers:
>
>  1) Fedora uses /etc/profile.d/git-prompt.sh.  Gentoo uses
>     /usr/share/bash-completion/git-prompt.  Maybe others use
>     some other path.
>
>  2) The scripts themselves suggest copying to ~/.git-completion.sh
>     and ~/.git-prompt.sh.
>
> Proposal:
>
>   1) /usr/lib/git-core/git-sh-prompt
>   2) git-sh-prompt(1)
>
> Sensible?

Does the LSB provide any guidance? If not, or if such guidance isn't helpful, I say that looks reasonable.

What I'd like to know is why we are saying "copy" when symlinking is likely to be more easily maintainable? (Less chance to screw up.)

-- 
-Drew Northup
--------------------------------------------------------------
"As opposed to vegetable or mineral error?"
-John Pescatore, SANS NewsBites Vol. 12 Num. 59
Danny Yates· Oct 25, 2012, 06:02 UTC · re: Jonathan Nieder · lore

Re: Where should git-prompt.sh be installed?

Would that not give the impression of "git sh-prompt" being a core command? If so, that would be poor, IMHO. 
When I was investigating this last night, I expected to find it (git-prompt.sh) in contrib, although that doesn't make an enormous amount of sense. Ideally, the full path to wherever it's installed should be mentioned in the bash completion file (which is where I went to look when __git_ps1 stopped working), but that would mean modifying a file from upstream and I'm not sure if that's easy/"the done thing".
Danny. 
On 25 Oct 2012, at 01:51, Jonathan Nieder <jrnieder@gmail.com> wrote:
Show 51 quoted lines
> Hi,
> 
> In olden days the admin would copy contrib/completion/git-completion.sh
> to
> 
>        /etc/bash_completion.d/git
> 
> and mortals could source /etc/bash_completion or
> /etc/bash_completion.d/git in their ~/.bashrc (possibly shared among
> multiple machines) so that the bash completion and __git_ps1 helpers
> could work.
> 
> With Git 1.7.12 __git_ps1 has been split into a separate file, to help
> users who only want __git_ps1 to avoid the overhead of loading the
> entire completion script (and allow the completion script to be loaded
> by bash-completion magic on the fly!).  Now the sysadmin should copy
> contrib/completion/git-completion.sh to
> 
>    /usr/share/bash-completion/completions/git
> 
> and contrib/completion/git-prompt.sh to
> 
>    /usr/share/git-core/contrib/?? (somewhere?)
> 
> Mortals source /etc/bash_completion in their ~/.bashrc (possibly
> shared among multiple machines) and expect bash completion to work.
> For __git_ps1, users should source that ?? path.
> 
> Questions:
> 
> 1) what path is appropriate for ?? above?
> 2) is this documented anywhere?
> 
> Possible answers:
> 
> 1) Fedora uses /etc/profile.d/git-prompt.sh.  Gentoo uses
>    /usr/share/bash-completion/git-prompt.  Maybe others use
>    some other path.
> 
> 2) The scripts themselves suggest copying to ~/.git-completion.sh
>    and ~/.git-prompt.sh.
> 
> Proposal:
> 
>  1) /usr/lib/git-core/git-sh-prompt
>  2) git-sh-prompt(1)
> 
> Sensible?
> 
> Thanks,
> Jonathan
Jonathan Nieder· Oct 25, 2012, 07:45 UTC · re: Danny Yates · lore

[RFC/PATCH] __git_ps1: migrate out of contrib/completion

Different installers put the git-prompt.sh shell library at different places on the installed system, so there is no shared location users can count on:

  Fedora - /etc/profile.d/git-prompt.sh
  Gentoo - /usr/share/bash-completion/git-prompt
  Arch - /usr/share/git/git-prompt.sh

The __git_ps1 helper doesn't have anything to do with bash completion in principle, but because it was written in the context of that project, its sources are kept in contrib/completion/git-prompt.sh. Let's make it a first-class shell library in the toplevel and install it to $(gitexecdir) alongside git-sh-setup and git-sh-i18n, where it can be easily found.

Keep a symlink in contrib/completion/ to avoid breaking setups where this library is used directly from the source tree.

Now you can put the following in your ~/.bashrc:
	if test "${BASH+set}" && test "${PS1+set}"	# interactive!
	then
		gitexecdir=$(git --exec-path)
		if test -r "$gitexecdir/git-sh-prompt)"
		then
			. "$gitexecdir/git-sh-prompt"
		fi
		if type -t __git_ps1 >/dev/null
		then
			PS1='\w$(__git_ps1)\$ '
		fi
	fi

and the shell prompt will show the current branch name in git repositories when on a machine with a new enough version of git.

Reported-by: Danny Yates <mail4danny@googlemail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Danny Yates wrote:
> Would that not give the impression of "git sh-prompt" being a core
> command? If so, that would be poor, IMHO. 
Not any more than $(git --exec-path)/git-sh-setup and git-sh-i18n. :)
Show 5 quoted lines
> When I was investigating this last night, I expected to find it
> (git-prompt.sh) in contrib, although that doesn't make an enormous
> amount of sense. Ideally, the full path to wherever it's installed
> should be mentioned in the bash completion file (which is where I
> went to look when __git_ps1 stopped working),
Yes, certainly.
>                                               but that would mean
> modifying a file from upstream and I'm not sure if that's easy/"the
> done thing".
We're talking on the upstream list now, so that's not an issue.

Thanks, Jonathan

 Documentation/git-sh-prompt.txt                    |  79 ++++++
 Makefile                                           |   1 +
 contrib/completion/git-completion.bash             |   2 +-
 contrib/completion/git-prompt.sh                   | 291 +--------------------
 .../completion/git-prompt.sh => git-sh-prompt.sh   |   0
 5 files changed, 82 insertions(+), 291 deletions(-)
 create mode 100644 Documentation/git-sh-prompt.txt
 rewrite contrib/completion/git-prompt.sh (100%)
 mode change 100644 => 120000
 rename contrib/completion/git-prompt.sh => git-sh-prompt.sh (100%)
Show changes to 4 files +82 −291

Documentation/git-sh-prompt.txt, Makefile, contrib/completion/git-completion.bash, contrib/completion/git-prompt.sh

diff --git a/Documentation/git-sh-prompt.txt b/Documentation/git-sh-prompt.txt
new file mode 100644
index 00000000..2c705fef
--- /dev/null
+++ b/Documentation/git-sh-prompt.txt
@@ -0,0 +1,79 @@
+git-sh-prompt(1)
+================
+
+NAME
+----
+git-sh-prompt - Functions to describe repository in bash or zsh prompt
+
+SYNOPSIS
+--------
+[verse]
+'. "$(git --exec-path)/git-sh-prompt"'
+
+DESCRIPTION
+-----------
+This script allows you to see the current branch in your bash prompt.
+
+To enable:
+
+1. Add the following line to your .bashrc and .zshrc:
+
+	. "$(git --exec-path)/git-sh-prompt"
+
+2. Change your PS1 to also show the current branch:
+
+	Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+	Zsh:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+
+The argument to __git_ps1 will only be displayed if you are currently
+in a git repository.  The %s token is replaced by the name of the current
+branch.
+
+In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
+unstaged (`*`) and staged (`+`) changes are indicated 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.
+
+You can also see if something is currently stashed, by setting
+GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+then a '$' is shown next to the branch name.
+
+If you would like to see if there are untracked files, set
+GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value.  If there are untracked
+files, a '%' is shown next to the branch name.
+
+If you would like to see the difference between HEAD and its upstream,
+set GIT_PS1_SHOWUPSTREAM=auto.  A '<' indicates the current branch is
+behind, '>' indicates it is ahead, '<>' indicates it has diverged, and
+'=' indicates no difference.  You can further control behavior by
+setting GIT_PS1_SHOWUPSTREAM to a space-separated list of values:
+
+verbose::
+	show number of commits ahead of/behind (+/-) upstream
+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 'git svn' upstream
+
+By default, __git_ps1 compares HEAD to your 'git 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 setting the `bash.showUpstream`
+config variable.
+
+FUNCTIONS
+---------
+
+'__gitdir' [<directory>]::
+	Print the path to the git repository (`.git` directory).  This is
+	similar to `git rev-parse --git-dir` but it is faster because it avoids
+	forking a new process when possible.
+
+'__git_ps1_show_upstream'::
+	Internal function.
+
+'__git_ps1 [<format>]'::
+	Print text to add to the shell's PS1 prompt, including the current
+	branch name.  If <format> is not specified, it defaults to " (%s)".
diff --git a/Makefile b/Makefile
index f69979e3..c12d973b 100644
--- a/Makefile
+++ b/Makefile
@@ -459,6 +459,7 @@ SCRIPT_LIB += git-rebase--interactive
 SCRIPT_LIB += git-rebase--merge
 SCRIPT_LIB += git-sh-setup
 SCRIPT_LIB += git-sh-i18n
+SCRIPT_LIB += git-sh-prompt
 
 SCRIPT_PERL += git-add--interactive.perl
 SCRIPT_PERL += git-difftool.perl
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index be800e09..01238588 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,7 +21,7 @@
 #    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-completion.sh
 #    3) Consider changing your PS1 to also show the current branch,
-#       see git-prompt.sh for details.
+#       see git-sh-prompt(1) for details.
 
 if [[ -n ${ZSH_VERSION-} ]]; then
 	autoload -U +X bashcompinit && bashcompinit
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
deleted file mode 100644
index bf20491e..00000000
--- a/contrib/completion/git-prompt.sh
+++ /dev/null
@@ -1,290 +0,0 @@
-# bash/zsh git prompt support
-#
-# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
-# Distributed under the GNU General Public License, version 2.0.
-#
-# This script allows you to see the current branch in your prompt.
-#
-# To enable:
-#
-#    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
-#    2) Add the following line to your .bashrc/.zshrc:
-#        source ~/.git-prompt.sh
-#    3) Change your PS1 to also show the current branch:
-#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
-#
-# 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.
-#
-# 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.
-#
-# You can also see if currently something is stashed, by setting
-# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
-# then a '$' will be shown next to the branch name.
-#
-# If you would like to see if there're untracked files, then you can set
-# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
-# files, then a '%' will be shown next to the branch name.
-#
-# If you would like to see the difference between HEAD and its upstream,
-# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
-# indicates you are ahead, "<>" indicates you have diverged and "="
-# indicates that there is no difference. You can further control
-# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
-# of values:
-#
-#     verbose       show number of commits ahead/behind (+/-) upstream
-#     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
-#
-# 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
-# setting the bash.showUpstream config variable.
-
-# __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
-}
-
-# stores the divergence from upstream in $p
-# used by GIT_PS1_SHOWUPSTREAM
-__git_ps1_show_upstream ()
-{
-	local key value
-	local svn_remote svn_url_pattern count n
-	local upstream=git legacy="" verbose=""
-
-	svn_remote=()
-	# get some config options from git-config
-	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
-	while read -r key value; do
-		case "$key" in
-		bash.showupstream)
-			GIT_PS1_SHOWUPSTREAM="$value"
-			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
-				p=""
-				return
-			fi
-			;;
-		svn-remote.*.url)
-			svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
-			svn_url_pattern+="\\|$value"
-			upstream=svn+git # default upstream is SVN if available, else git
-			;;
-		esac
-	done <<< "$output"
-
-	# parse configuration values
-	for option in ${GIT_PS1_SHOWUPSTREAM}; do
-		case "$option" in
-		git|svn) upstream="$option" ;;
-		verbose) verbose=1 ;;
-		legacy)  legacy=1  ;;
-		esac
-	done
-
-	# Find our upstream
-	case "$upstream" in
-	git)    upstream="@{upstream}" ;;
-	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 \
-					--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%@*}
-			local n_stop="${#svn_remote[@]}"
-			for ((n=1; n <= n_stop; n++)); do
-				svn_upstream=${svn_upstream#${svn_remote[$n]}}
-			done
-
-			if [[ -z "$svn_upstream" ]]; then
-				# default branch name for checkouts with no layout:
-				upstream=${GIT_SVN_ID:-git-svn}
-			else
-				upstream=${svn_upstream#/}
-			fi
-		elif [[ "svn+git" = "$upstream" ]]; then
-			upstream="@{upstream}"
-		fi
-		;;
-	esac
-
-	# Find how many commits we are ahead/behind our upstream
-	if [[ -z "$legacy" ]]; then
-		count="$(git rev-list --count --left-right \
-				"$upstream"...HEAD 2>/dev/null)"
-	else
-		# produce equivalent output to --count for older versions of git
-		local commits
-		if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
-		then
-			local commit behind=0 ahead=0
-			for commit in $commits
-			do
-				case "$commit" in
-				"<"*) ((behind++)) ;;
-				*)    ((ahead++))  ;;
-				esac
-			done
-			count="$behind	$ahead"
-		else
-			count=""
-		fi
-	fi
-
-	# calculate the result
-	if [[ -z "$verbose" ]]; then
-		case "$count" in
-		"") # no upstream
-			p="" ;;
-		"0	0") # equal to upstream
-			p="=" ;;
-		"0	"*) # ahead of upstream
-			p=">" ;;
-		*"	0") # behind upstream
-			p="<" ;;
-		*)	    # diverged from upstream
-			p="<>" ;;
-		esac
-	else
-		case "$count" in
-		"") # no upstream
-			p="" ;;
-		"0	0") # equal to upstream
-			p=" u=" ;;
-		"0	"*) # ahead of upstream
-			p=" u+${count#0	}" ;;
-		*"	0") # behind upstream
-			p=" u-${count%	0}" ;;
-		*)	    # diverged from upstream
-			p=" u+${count#*	}-${count%	*}" ;;
-		esac
-	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="$(__gitdir)"
-	if [ -n "$g" ]; then
-		local r=""
-		local b=""
-		if [ -f "$g/rebase-merge/interactive" ]; then
-			r="|REBASE-i"
-			b="$(cat "$g/rebase-merge/head-name")"
-		elif [ -d "$g/rebase-merge" ]; then
-			r="|REBASE-m"
-			b="$(cat "$g/rebase-merge/head-name")"
-		else
-			if [ -d "$g/rebase-apply" ]; then
-				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/BISECT_LOG" ]; then
-				r="|BISECTING"
-			fi
-
-			b="$(git symbolic-ref HEAD 2>/dev/null)" || {
-
-				b="$(
-				case "${GIT_PS1_DESCRIBE_STYLE-}" in
-				(contains)
-					git describe --contains HEAD ;;
-				(branch)
-					git describe --contains --all HEAD ;;
-				(describe)
-					git describe HEAD ;;
-				(* | default)
-					git describe --tags --exact-match HEAD ;;
-				esac 2>/dev/null)" ||
-
-				b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
-				b="unknown"
-				b="($b)"
-			}
-		fi
-
-		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:"
-			else
-				b="GIT_DIR!"
-			fi
-		elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
-			if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
-				if [ "$(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
-			fi
-			if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
-				git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
-			fi
-
-			if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
-				if [ -n "$(git ls-files --others --exclude-standard)" ]; then
-					u="%"
-				fi
-			fi
-
-			if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
-				__git_ps1_show_upstream
-			fi
-		fi
-
-		local f="$w$i$s$u"
-		printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
-	fi
-}
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
new file mode 120000
index 00000000..a4fbb216
--- /dev/null
+++ b/contrib/completion/git-prompt.sh
@@ -0,0 +1 @@
+../../git-sh-prompt.sh
\ No newline at end of file
diff --git a/contrib/completion/git-prompt.sh b/git-sh-prompt.sh
similarity index 100%
rename from contrib/completion/git-prompt.sh
rename to git-sh-prompt.sh
-- 
1.8.0
Felipe Contreras· Oct 25, 2012, 14:19 UTC · re: Jonathan Nieder · lore

Re: [RFC/PATCH] __git_ps1: migrate out of contrib/completion

On Thu, Oct 25, 2012 at 9:45 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:
Show 8 quoted lines
> diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
> new file mode 120000
> index 00000000..a4fbb216
> --- /dev/null
> +++ b/contrib/completion/git-prompt.sh
> @@ -0,0 +1 @@
> +../../git-sh-prompt.sh
> \ No newline at end of file
^ no new line?
-- 
Felipe Contreras
Todd Zullinger· Nov 8, 2012, 13:19 UTC · re: Jonathan Nieder · lore

Re: [RFC/PATCH] __git_ps1: migrate out of contrib/completion

Jonathan Nieder wrote:
Show 5 quoted lines
> Different installers put the git-prompt.sh shell library at different 
> places on the installed system, so there is no shared location users 
> can count on:
>
>  Fedora - /etc/profile.d/git-prompt.sh

FWIW, we moved it to /usr/share/git-core/contrib/completion/ -- it was only ever in /etc/profile.d in an unreleased version of Fedora for a short time. (Side note: at some point, we'll likely install most or all of contrib under /usr/share/git-core/contrib in Fedora.)

Having it in a more standard location would be excellent, it would avoid bugs like: https://bugzilla.redhat.com/show_bug.cgi?id=854061 :)

-- 
Todd        OpenPGP -> KeyID: 0xBEAF0CE3 | URL: www.pobox.com/~tmz/pgp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Oh, very funny!  Now tell the one that doesn't suck.
       -- Stewie Griffin
Anders Kaseorg· Oct 25, 2012, 08:10 UTC · re: Danny Yates · lore

Re: Where should git-prompt.sh be installed?

On 10/25/2012 02:02 AM, Danny Yates wrote:
> Would that not give the impression of "git sh-prompt" being a core
> command?

No more than git-sh-setup, which already works like that. Unless perhaps by “core” you mean “not contrib”.

(Now that I think of it, I saw a request from an Ubuntu PPA user last week to install git-subtree in a more accessible location, and there’s a similar request about gitview at https://bugs.launchpad.net/bugs/152212 . These are less critical since the Debian package puts them in /usr/share/doc/git/contrib. Is it a good idea to package those somewhere like /usr/lib/git-core or /usr/bin, or is that a dangerous slippery slope? I dunno.)

Anders
SZEDER Gábor· Oct 25, 2012, 15:11 UTC · re: Jonathan Nieder · lore

Re: Where should git-prompt.sh be installed?

On Wed, Oct 24, 2012 at 05:51:06PM -0700, Jonathan Nieder wrote:
Show 11 quoted lines
> Hi,
> 
> In olden days the admin would copy contrib/completion/git-completion.sh
> to
> 
>         /etc/bash_completion.d/git
> 
> and mortals could source /etc/bash_completion or
> /etc/bash_completion.d/git in their ~/.bashrc (possibly shared among
> multiple machines) so that the bash completion and __git_ps1 helpers
> could work.

Ah, the good old days! I even modified 'make install' to copy the completion script to /etc/bash_completion.d/. And I was happy.

Show 20 quoted lines
> With Git 1.7.12 __git_ps1 has been split into a separate file, to help
> users who only want __git_ps1 to avoid the overhead of loading the
> entire completion script (and allow the completion script to be loaded
> by bash-completion magic on the fly!).  Now the sysadmin should copy
> contrib/completion/git-completion.sh to
> 
> 	/usr/share/bash-completion/completions/git
> 
> and contrib/completion/git-prompt.sh to
> 
> 	/usr/share/git-core/contrib/?? (somewhere?)
> 
> Mortals source /etc/bash_completion in their ~/.bashrc (possibly
> shared among multiple machines) and expect bash completion to work.
> For __git_ps1, users should source that ?? path.
> 
> Questions:
> 
>  1) what path is appropriate for ?? above?
>  2) is this documented anywhere?

Don't know what is appropriate, and it's not documented. I for one copy it manually to ~/.git-prompt.sh every once in a while. And I'm not all that happy with that.

Show 13 quoted lines
> Possible answers:
> 
>  1) Fedora uses /etc/profile.d/git-prompt.sh.  Gentoo uses
>     /usr/share/bash-completion/git-prompt.  Maybe others use
>     some other path.
> 
>  2) The scripts themselves suggest copying to ~/.git-completion.sh
>     and ~/.git-prompt.sh.
> 
> Proposal:
> 
>   1) /usr/lib/git-core/git-sh-prompt
>   2) git-sh-prompt(1)

Not sure about the "sh" part. The prompt function is very Bash-specific, it won't work under a plain POSIX shell.

Do other VCSes have similar prompt scripts? Where do they install theirs?

Gábor
Jonathan Nieder· Oct 25, 2012, 16:12 UTC · re: SZEDER Gábor · lore

Re: Where should git-prompt.sh be installed?

SZEDER Gábor wrote:
> On Wed, Oct 24, 2012 at 05:51:06PM -0700, Jonathan Nieder wrote:
Show 7 quoted lines
>> Proposal:
>>
>>   1) /usr/lib/git-core/git-sh-prompt
>>   2) git-sh-prompt(1)
>
> Not sure about the "sh" part.  The prompt function is very
> Bash-specific, it won't work under a plain POSIX shell.
That's an interesting point.  Here's my logic:

The prompt function was originally Bash-specific, but over time it gained support for Zsh as well. If we're lucky, some day it might gain support for mksh.

Meanwhile something simple like "git-prompt" would sound too much like a normal git command, I fear.

Shell language extensions used:
 * future standard: local variables
 * cosmetic: [[ and (( syntax in place of test and $(
 * cosmetic: for ((n=1; n <= n_stop; n++)) instead of a more explicit
   while loop
 * cosmetic: var+=value syntax
 * optimization: <<< syntax to iterate over lines in a variable
   instead of, for example, sed + eval
 * arrays: svn_remote, svn_upstream --- using plain variables would
   require some escaping.

So nothing fundamental, but since this is only useful in shells like Bash that support command substitution in $PS1, it seems reasonable to keep using the extensions until someone wants to use it with a more limited shell.

In other words, the interface is still "this is a scriptlet you might source in your Bourne-style shell to get a __git_ps1 function to use in your prompt". The implementation language just happens not to be POSIX shell today.

Perhaps it should return early in shells other than bash and zsh to help people keep their .shrc simple. What do you think?

> Do other VCSes have similar prompt scripts?  Where do they install
> theirs?

Mercurial has an hg-prompt extension that can be used by running "hg prompt". http://mercurial.selenic.com/wiki/PromptExtension

I haven't found one for Subversion.
Bazaar has contrib/bash/bzrbashprompt.sh.  It doesn't get installed.

Thanks, Jonathan

Junio C Hamano· May 23, 2012, 16:33 UTC · re: Felipe Contreras · lore

Re: [PATCH 0/2] completion: split into git-prompt.sh

Thanks for tying the loose ends.

The update to t9903 in the second patch is a bit tricky to handle, though. By the time both series graduate, somebody has to tell t9903 where to find the git-prompt scriptlet, but by basing it on 'pu', you made this series a hostage to the still-incomplete bash-prompt update series by SZEDER Gábor

I think merging the bottom-most two commits in sg/bash-prompt series and the tip of fc/git-complete-helper-fix and then applying these two patches on top would be the easiest for me to handle, but if you or anybody else think of a better organization, please speak up.

Thanks.
SZEDER Gábor· May 25, 2012, 07:35 UTC · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Thu, May 24, 2012 at 11:36:45PM -0400, Ted Pavlic wrote:
Show 6 quoted lines
> > You mean a real git command, which does the same as __gitdir()?  I
> > don't like that, because it will always require 2 fork()s and an
> > exec() and would be slow on Windows.
> 
> Interesting. I guess I didn't realize bash completion was an issue for most
> Windows users. Is it?

It is. Emulating fork() and exec() is very expensive, so every subshell, external command, or especially git command in a command substitution costs dearly. And the completion script uses many git commands and even more subshells.

Case in point is __git_ps1() and __gitdir(). There are scenarios where displaying the git-specific bash prompt takes more than 400ms on Windows, while displaying the same prompt takes only about 26ms on Linux on the same hardware.

  http://thread.gmane.org/gmane.comp.version-control.git/197432

Best, Gábor

Thomas Rast· May 25, 2012, 07:50 UTC · re: SZEDER Gábor · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

SZEDER Gábor <szeder@ira.uka.de> writes:
Show 19 quoted lines
> On Thu, May 24, 2012 at 11:36:45PM -0400, Ted Pavlic wrote:
>> > You mean a real git command, which does the same as __gitdir()?  I
>> > don't like that, because it will always require 2 fork()s and an
>> > exec() and would be slow on Windows.
>> 
>> Interesting. I guess I didn't realize bash completion was an issue for most
>> Windows users. Is it?
>
> It is.  Emulating fork() and exec() is very expensive, so every
> subshell, external command, or especially git command in a command
> substitution costs dearly.  And the completion script uses many git
> commands and even more subshells.
>
> Case in point is __git_ps1() and __gitdir().  There are scenarios
> where displaying the git-specific bash prompt takes more than 400ms on
> Windows, while displaying the same prompt takes only about 26ms on
> Linux on the same hardware.
>
>   http://thread.gmane.org/gmane.comp.version-control.git/197432

Why not make a git builtin command that figures out everything that __git_ps1 does? Perhaps in a format that can be eval'd and processed to the user's taste.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch
Felipe Contreras· May 25, 2012, 10:01 UTC · re: Thomas Rast · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

On Fri, May 25, 2012 at 9:50 AM, Thomas Rast <trast@inf.ethz.ch> wrote:
Show 25 quoted lines
> SZEDER Gábor <szeder@ira.uka.de> writes:
>
>> On Thu, May 24, 2012 at 11:36:45PM -0400, Ted Pavlic wrote:
>>> > You mean a real git command, which does the same as __gitdir()?  I
>>> > don't like that, because it will always require 2 fork()s and an
>>> > exec() and would be slow on Windows.
>>>
>>> Interesting. I guess I didn't realize bash completion was an issue for most
>>> Windows users. Is it?
>>
>> It is.  Emulating fork() and exec() is very expensive, so every
>> subshell, external command, or especially git command in a command
>> substitution costs dearly.  And the completion script uses many git
>> commands and even more subshells.
>>
>> Case in point is __git_ps1() and __gitdir().  There are scenarios
>> where displaying the git-specific bash prompt takes more than 400ms on
>> Windows, while displaying the same prompt takes only about 26ms on
>> Linux on the same hardware.
>>
>>   http://thread.gmane.org/gmane.comp.version-control.git/197432
>
> Why not make a git builtin command that figures out everything that
> __git_ps1 does?  Perhaps in a format that can be eval'd and processed to
> the user's taste.
That is what I was thinking.
-- 
Felipe Contreras
Junio C Hamano· May 25, 2012, 18:03 UTC · re: Thomas Rast · lore

Re: [PATCH 2/2] completion: split __git_ps1 into a separate script

Thomas Rast <trast@inf.ethz.ch> writes:
> Why not make a git builtin command that figures out everything that
> __git_ps1 does?  Perhaps in a format that can be eval'd and processed to
> the user's taste.

I'd rather not to see something so specific for one interpreter like that in the core. How about doing it this way instead?

Show changes to 6 files +39 −39

contrib/completion/Makefile, contrib/completion/common-bits, contrib/completion/git-completion.bash, contrib/completion/git-completion.bash.shc, contrib/completion/git-prompt.sh, contrib/completion/git-prompt.sh.shc

diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile
new file mode 100644
index 0000000..71c600f
--- /dev/null
+++ b/contrib/completion/Makefile
@@ -0,0 +1,13 @@
+# The default target is ...
+all::
+
+SCRIPTS = git-completion.bash git-prompt.sh
+
+all:: $(SCRIPTS)
+clean::
+	rm -f $(SCRIPTS)
+
+$(SCRIPTS): % : %.shc
+	rm -f $@+ $@
+	sed -e '/## include common-bits/r common-bits' $< >$@+
+	mv $@+ $@
diff --git a/contrib/completion/common-bits b/contrib/completion/common-bits
new file mode 100644
index 0000000..06c2845
--- /dev/null
+++ b/contrib/completion/common-bits
@@ -0,0 +1,22 @@
+# __gitdir accepts 0 or 1 arguments (i.e., location)
+# returns location of .git repo
+__gitdir ()
+{
+	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
+}
+
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash.shc
similarity index 99%
rename from contrib/completion/git-completion.bash
rename to contrib/completion/git-completion.bash.shc
index abf8215..cf30f01 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash.shc
@@ -32,24 +32,8 @@ 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 [ -n "${__git_dir-}" ]; then
-			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
-}
+## include common-bits here
+## common-bits ends here
 
 __gitcomp_1 ()
 {
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh.shc
similarity index 94%
rename from contrib/completion/git-prompt.sh
rename to contrib/completion/git-prompt.sh.shc
index 8e2e9f3..d442a1a 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh.shc
@@ -49,27 +49,8 @@
 # GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
 # setting the bash.showUpstream config variable.
 
-# __gitdir accepts 0 or 1 arguments (i.e., location)
-# returns location of .git repo
-__gitdir ()
-{
-	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
-}
+## include common-bits here
+## common-bits ends here
 
 # stores the divergence from upstream in $p
 # used by GIT_PS1_SHOWUPSTREAM

← back to recent threads