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

[PATCH] squash! completion: fill COMPREPLY directly when completing refs

From
SZEDER Gábor <szeder.dev@gmail.com>
Date
Feb 6, 2017, 18:15 UTC
Message-ID
<20170206181545.12869-1-szeder.dev@gmail.com>
In-Reply-To
<20170203025405.8242-13-szeder.dev@gmail.com>

Care should be taken, though, because that prefix might contain 'for-each-ref' format specifiers as part of the left hand side of a '..' range or '...' symmetric difference notation or fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'. Doubling every '%' in the prefix will prevent 'git for-each-ref' from interpolating any of those contained format specifiers. ---

This is really pathological, and I'm sure this has nothing to do with whatever breakage Jacob experienced. The shell metacharacters '(' and ')' still cause us trouble in various ways, but that's nothing new and has been the case for quite a while (always?).

It's already incorporated into (the rewritten)
  https://github.com/szeder/git completion-refs-speedup
 contrib/completion/git-completion.bash |  8 +++++---
 t/t9902-completion.sh                  | 11 +++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index dbbb62f5f..058f1d0ee 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -381,6 +381,7 @@ __git_refs ()
 	local list_refs_from=path remote="${1-}"
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
+	local fer_pfx="${pfx//\%/%%}"
 
 	__git_find_repo_path
 	dir="$__git_repo_path"
@@ -406,6 +407,7 @@ __git_refs ()
 	if [ "$list_refs_from" = path ]; then
 		if [[ "$cur_" == ^* ]]; then
 			pfx="$pfx^"
+			fer_pfx="$fer_pfx^"
 			cur_=${cur_#^}
 		fi
 		case "$cur_" in
@@ -429,13 +431,13 @@ __git_refs ()
 				"refs/remotes/$cur_*" "refs/remotes/$cur_*/**")
 			;;
 		esac
-		__git_dir="$dir" __git for-each-ref --format="$pfx%($format)$sfx" \
+		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
 			"${refs[@]}"
 		if [ -n "$track" ]; then
 			# employ the heuristic used by git checkout
 			# Try to find a remote branch that matches the completion word
 			# but only output if the branch name is unique
-			__git for-each-ref --format="$pfx%(refname:strip=3)$sfx" \
+			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 				--sort="refname:strip=3" \
 				"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
 			uniq -u
@@ -457,7 +459,7 @@ __git_refs ()
 			case "HEAD" in
 			$cur_*)	echo "${pfx}HEAD$sfx" ;;
 			esac
-			__git for-each-ref --format="$pfx%(refname:strip=3)$sfx" \
+			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 				"refs/remotes/$remote/$cur_*" \
 				"refs/remotes/$remote/$cur_*/**"
 		else
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 1206a38ed..be584c069 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -951,6 +951,17 @@ test_expect_success 'teardown after filtering matching refs' '
 	git update-ref -d refs/remotes/other/matching/branch-in-other
 '
 
+test_expect_success '__git_refs - for-each-ref format specifiers in prefix' '
+	cat >expected <<-EOF &&
+	evil-%%-%42-%(refname)..master
+	EOF
+	(
+		cur="evil-%%-%42-%(refname)..mas" &&
+		__git_refs "" "" "evil-%%-%42-%(refname).." mas >"$actual"
+	) &&
+	test_cmp expected "$actual"
+'
+
 test_expect_success '__git_complete_refs - simple' '
 	sed -e "s/Z$//g" >expected <<-EOF &&
 	HEAD Z
-- 
2.11.1.499.gb6fcc8b3a
Previous: SZEDER GáborNext: Junio C Hamano
Message 8 of 23 in “completion: speed up refs completion”
  1. 00/12 completion: speed up refs completionSZEDER Gábor, Feb 3, 2017
  2. 01/12 completion: remove redundant __gitcomp_nl() options from _git_commit()SZEDER Gábor, Feb 3, 2017
  3. 02/12 completion: wrap __git_refs() for better option parsingSZEDER Gábor, Feb 3, 2017
  4. 07/12 completion: let 'for-each-ref' and 'ls-remote' filter matching refsSZEDER Gábor, Feb 3, 2017
  5. 03/12 completion: support completing full refs after '--option=refs/<TAB>'SZEDER Gábor, Feb 3, 2017
  6. 08/12 completion: let 'for-each-ref' strip the remote name from remote branchesSZEDER Gábor, Feb 3, 2017
  7. 12/12 completion: fill COMPREPLY directly when completing refsSZEDER Gábor, Feb 3, 2017
  8. squash! completion: fill COMPREPLY directly when completing refsSZEDER Gábor, Feb 6, 2017
  9. Junio C HamanoFeb 10, 2017
  10. SZEDER GáborFeb 13, 2017
  11. Junio C HamanoFeb 13, 2017
  12. 10/12 completion: let 'for-each-ref' sort remote branches for 'checkout' DWIMerySZEDER Gábor, Feb 3, 2017
  13. 11/12 completion: list only matching symbolic and pseudorefs when completing refsSZEDER Gábor, Feb 3, 2017
  14. 06/12 completion: don't disambiguate short refsSZEDER Gábor, Feb 3, 2017
  15. 04/12 completion: support excluding full refsSZEDER Gábor, Feb 3, 2017
  16. 05/12 completion: don't disambiguate tags and branchesSZEDER Gábor, Feb 3, 2017
  17. 09/12 completion: let 'for-each-ref' filter remote branches for 'checkout' DWIMerySZEDER Gábor, Feb 3, 2017
  18. Jacob KellerFeb 3, 2017
  19. Jacob KellerFeb 4, 2017
  20. Junio C HamanoFeb 4, 2017
  21. Jacob KellerFeb 6, 2017
  22. SZEDER GáborFeb 6, 2017
  23. Jacob KellerFeb 6, 2017

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.