git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 3/8] git-prompt: don't use shell arrays

From
AGAvi Halachmi (:avih) via GitGitGadget <gitgitgadget@gmail.com>
Date
Jul 23, 2024, 19:18 UTC
Message-ID
<7e994eae7bc3dfa021262410c801ddb124ce24f1.1721762306.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1750.git.git.1721762306.gitgitgadget@gmail.com>
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Arrays only existed in the svn-upstream code, used to:
- Keep a list of svn remotes.
- Convert commit msg to array of words, extract the 2nd-to-last word.
Except bash/zsh, nearly all shells failed load on syntax errors here.
Now:
- The svn remotes are a list of newline-terminated values.
- The 2nd-to-last word is extracted using standard shell substrings.
- All shells can digest the svn-upstream code.

While using shell field splitting to extract the word is simple, and doesn't even need non-standard code, e.g. set -- $(git log -1 ...), it would have the same issues as the old array code: it depends on IFS which we don't control, and it's subject to glob-expansion, e.g. if the message happens to include * or **/* (as this commit message just did), then the array could get huge. This was not great.

Now it uses standard shell substrings, and we know the exact delimiter to expect, because it's the match from our grep just one line earlier.

The new word extraction code also fixes svn-upstream in zsh, because previously it used arr[len-2], but because in zsh, unlike bash, array subscripts are 1-based, it incorrectly extracted the 3rd-to-last word. symptom: missing upstream status in a git-svn repo: u=, u+N-M, etc.

The breakage in zsh is surprising, because it was last touched by
  commit d0583da838 (prompt: fix show upstream with svn and zsh),
claiming to fix exactly that. However, it only mentions syntax fixes.
It's unclear if behavior was fixed too. But it was broken, now fixed.

Note LF=$'\n' and then using $LF instead of $'\n' few times. A future commit will add fallback for shells without $'...', so this would be the only line to touch instead of replacing every $'\n' .

Shells which could run the previous array code:
- bash
Shells which have arrays but were broken anyway:
- zsh: 1-based subscript
- ksh93: no "local" (the new code can't fix this part...)
- mksh, openbsd sh, pdksh: failed load on syntax error: "for ((...))".
More shells which Failed to load due to syntax error:
- dash, free/net bsd sh, busybox-ash, Schily Bourne shell, yash.
Signed-off-by: Avi Halachmi (:avih) <avihpit@yahoo.com>
---
 contrib/completion/git-prompt.sh | 48 ++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 4cc2cf91bb6..75c3a813fda 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -116,10 +116,10 @@ printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
 __git_ps1_show_upstream ()
 {
 	local key value
-	local svn_remote svn_url_pattern="" count n
+	local svn_remotes="" svn_url_pattern="" count n
 	local upstream_type=git legacy="" verbose="" name=""
+	local LF=$'\n'
 
-	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
@@ -132,7 +132,7 @@ __git_ps1_show_upstream ()
 			fi
 			;;
 		svn-remote.*.url)
-			svn_remote[$((${#svn_remote[@]} + 1))]="$value"
+			svn_remotes=${svn_remotes}${value}${LF}  # URI\nURI\n...
 			svn_url_pattern="$svn_url_pattern\\|$value"
 			upstream_type=svn+git # default upstream type is SVN if available, else git
 			;;
@@ -156,25 +156,37 @@ __git_ps1_show_upstream ()
 	case "$upstream_type" in
 	git)    upstream_type="@{upstream}" ;;
 	svn*)
-		# get the upstream from the "git-svn-id: ..." in a commit message
-		# (git-svn uses essentially the same procedure internally)
-		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%@*}
-			local n_stop="${#svn_remote[@]}"
-			for ((n=1; n <= n_stop; n++)); do
-				svn_upstream=${svn_upstream#${svn_remote[$n]}}
-			done
+		# successful svn-upstream resolution:
+		# - get the list of configured svn-remotes ($svn_remotes set above)
+		# - get the last commit which seems from one of our svn-remotes
+		# - confirm that it is from one of the svn-remotes
+		# - use $GIT_SVN_ID if set, else "git-svn"
 
-			if [[ -z "$svn_upstream" ]]; then
+		# get upstream from "git-svn-id: UPSTRM@N HASH" 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 [ -n "$svn_upstream" ]; then
+			# extract the URI, assuming --grep matched the last line
+			svn_upstream=${svn_upstream##*$LF}  # last line
+			svn_upstream=${svn_upstream#*: }    # UPSTRM@N HASH
+			svn_upstream=${svn_upstream%@*}     # UPSTRM
+
+			case ${LF}${svn_remotes} in
+			*"${LF}${svn_upstream}${LF}"*)
+				# grep indeed matched the last line - it's our remote
 				# default branch name for checkouts with no layout:
 				upstream_type=${GIT_SVN_ID:-git-svn}
-			else
+				;;
+			*)
+				# the commit message includes one of our remotes, but
+				# it's not at the last line. is $svn_upstream junk?
 				upstream_type=${svn_upstream#/}
-			fi
+				;;
+			esac
 		elif [[ "svn+git" = "$upstream_type" ]]; then
 			upstream_type="@{upstream}"
 		fi
-- 
gitgitgadget
Previous: Avi Halachmi (:avih) via GitGitGadgetNext: Avi Halachmi (:avih) via GitGitGadget
Message 4 of 80 in “git-prompt: support more shells”
  1. 0/8 git-prompt: support more shellsAvi Halachmi via GitGitGadget, Jul 23, 2024
  2. 1/8 git-prompt: use here-doc instead of here-stringAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  3. 2/8 git-prompt: fix uninitialized variableAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  4. 3/8 git-prompt: don't use shell arraysAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  5. 4/8 git-prompt: replace [[...]] with standard codeAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  6. 5/8 git-prompt: add some missing quotesAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  7. Junio C HamanoJul 23, 2024
  8. avihJul 24, 2024
  9. 6/8 git-prompt: add fallback for shells without $'...'Avi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  10. Junio C HamanoJul 23, 2024
  11. avihJul 24, 2024
  12. avihJul 25, 2024
  13. avihJul 25, 2024
  14. Junio C HamanoJul 25, 2024
  15. avihJul 25, 2024
  16. Junio C HamanoJul 25, 2024
  17. avihAug 14, 2024
  18. Junio C HamanoAug 14, 2024
  19. avihAug 15, 2024
  20. Junio C HamanoAug 15, 2024
  21. 7/8 git-prompt: ta-da! document usage in other shellsAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  22. 8/8 git-prompt: support custom 0-width PS1 markersAvi Halachmi (:avih) via GitGitGadget, Jul 23, 2024
  23. brian m. carlsonJul 23, 2024
  24. avihJul 24, 2024
  25. Junio C HamanoJul 24, 2024
  26. Junio C HamanoJul 24, 2024
  27. avihJul 24, 2024
  28. 0/8 git-prompt: support more shells v2Avi Halachmi via GitGitGadget, Aug 15, 2024
  29. 1/8 git-prompt: use here-doc instead of here-stringAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  30. Patrick SteinhardtAug 16, 2024
  31. avihAug 16, 2024
  32. Patrick SteinhardtAug 16, 2024
  33. 2/8 git-prompt: fix uninitialized variableAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  34. 3/8 git-prompt: don't use shell arraysAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  35. Patrick SteinhardtAug 16, 2024
  36. avihAug 16, 2024
  37. Patrick SteinhardtAug 16, 2024
  38. avihAug 16, 2024
  39. Patrick SteinhardtAug 16, 2024
  40. 4/8 git-prompt: replace [[...]] with standard codeAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  41. Junio C HamanoAug 15, 2024
  42. avihAug 16, 2024
  43. Junio C HamanoAug 16, 2024
  44. 5/8 git-prompt: add some missing quotesAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  45. Junio C HamanoAug 15, 2024
  46. avihAug 15, 2024
  47. Junio C HamanoAug 15, 2024
  48. avihAug 15, 2024
  49. 6/8 git-prompt: don't use shell $'...'Avi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  50. 7/8 git-prompt: ta-da! document usage in other shellsAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  51. Patrick SteinhardtAug 16, 2024
  52. avihAug 16, 2024
  53. 8/8 git-prompt: support custom 0-width PS1 markersAvi Halachmi (:avih) via GitGitGadget, Aug 15, 2024
  54. Junio C HamanoAug 15, 2024
  55. Patrick SteinhardtAug 16, 2024
  56. 0/8 git-prompt: support more shells v3Avi Halachmi via GitGitGadget, Aug 17, 2024
  57. 1/8 git-prompt: use here-doc instead of here-stringAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  58. 2/8 git-prompt: fix uninitialized variableAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  59. 3/8 git-prompt: don't use shell arraysAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  60. 4/8 git-prompt: replace [[...]] with standard codeAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  61. 5/8 git-prompt: add some missing quotesAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  62. Eric SunshineAug 17, 2024
  63. avihAug 17, 2024
  64. Junio C HamanoAug 17, 2024
  65. avihAug 17, 2024
  66. 6/8 git-prompt: don't use shell $'...'Avi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  67. 7/8 git-prompt: ta-da! document usage in other shellsAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  68. 8/8 git-prompt: support custom 0-width PS1 markersAvi Halachmi (:avih) via GitGitGadget, Aug 17, 2024
  69. 0/8 git-prompt: support more shells v4Avi Halachmi via GitGitGadget, Aug 20, 2024
  70. 1/8 git-prompt: use here-doc instead of here-stringAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  71. 2/8 git-prompt: fix uninitialized variableAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  72. 3/8 git-prompt: don't use shell arraysAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  73. 4/8 git-prompt: replace [[...]] with standard codeAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  74. 5/8 git-prompt: add some missing quotesAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  75. 6/8 git-prompt: don't use shell $'...'Avi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  76. 7/8 git-prompt: ta-da! document usage in other shellsAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  77. 8/8 git-prompt: support custom 0-width PS1 markersAvi Halachmi (:avih) via GitGitGadget, Aug 20, 2024
  78. Junio C HamanoAug 20, 2024
  79. avihAug 20, 2024
  80. avihAug 28, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.