Skip to contentSkip to conversation

add case insensitivity option to bash completion

PATCH Superseded Alison Winters via GitGitGadget 6 participants 15 messages Nov 5, 2022 – Nov 30, 2022

lore
Share & tools
lore
#0 lore raw

cover add case insensitivity option to bash completion

In 3bb16a8bf2 (tag, branch, for-each-ref: add --ignore-case for sorting and filtering, 2016-12-04), support was added for filtering and sorting refs in a case insensitive way. This is a behavior that seems appropriate to enable with shell completion. Many shells provide case insensitive completion as an option, even on filesystems that remain case sensitive.

This patch adds a new variable that, when set, will allow Bash completion to use the --ignore-case option to match refs. Additionally, some basic support is implemented to match pseudorefs like HEAD.

Alison Winters (2):
completion: add optional ignore-case when matching refs
completion: add case-insensitive match of pseudorefs

 contrib/completion/git-completion.bash | 51 ++++++++++++++++++++++++--
 t/t9902-completion.sh                  | 32 ++++++++++++++++
 2 files changed, 80 insertions(+), 3 deletions(-)

base-commit: 3b08839926fcc7cc48cf4c759737c1a71af430c1
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1374%2Falisonatwork%2Fbash-insensitive-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1374/alisonatwork/bash-insensitive-v1
Pull-Request: https://github.com/git/git/pull/1374

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/2 completion: add optional ignore-case when matching refs

From: Alison Winters <[email protected]>

If GIT_COMPLETION_IGNORE_CASE=1 is set, --ignore-case will be added to git for-each-ref calls so that branches and tags can be matched case insensitively.

---
 contrib/completion/git-completion.bash | 41 ++++++++++++++++++++++++++
 t/t9902-completion.sh                  | 16 ++++++++++
 2 files changed, 57 insertions(+)
contrib/completion/git-completion.bash +41 -0
index ba5c395d2d8..8ed96a5b8b6 100644
@@ -58,6 +58,11 @@
 #
 #     When set to "1" suggest all options, including options which are
 #     typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+#   GIT_COMPLETION_IGNORE_CASE
+#
+#     When set to "1", suggest refs that match case insensitively (e.g.,
+#     completing "FOO" on "git checkout f<TAB>").
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -644,8 +649,15 @@ __git_complete_index_file ()
 __git_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \
 			"refs/heads/$cur_*" "refs/heads/$cur_*/**"
 }
 
@@ -657,8 +669,15 @@ __git_heads ()
 __git_remote_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \
 			"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
 }
 
@@ -667,8 +686,15 @@ __git_remote_heads ()
 __git_tags ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \
 			"refs/tags/$cur_*" "refs/tags/$cur_*/**"
 }
 
@@ -682,12 +708,19 @@ __git_dwim_remote_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	# employ the heuristic used by git checkout and git switch
 	# Try to find a remote branch that cur_es the completion word
 	# but only output if the branch name is unique
 	__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 		--sort="refname:strip=3" \
+		$ignore_case \
 		"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
 	uniq -u
 }
@@ -713,6 +746,7 @@ __git_refs ()
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+	local ignore_case=""
 
 	__git_find_repo_path
 	dir="$__git_repo_path"
@@ -735,6 +769,11 @@ __git_refs ()
 		fi
 	fi
 
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
+
 	if [ "$list_refs_from" = path ]; then
 		if [[ "$cur_" == ^* ]]; then
 			pfx="$pfx^"
@@ -765,6 +804,7 @@ __git_refs ()
 			;;
 		esac
 		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+			$ignore_case \
 			"${refs[@]}"
 		if [ -n "$track" ]; then
 			__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -787,6 +827,7 @@ __git_refs ()
 			$match*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+				$ignore_case \
 				"refs/remotes/$remote/$match*" \
 				"refs/remotes/$remote/$match*/**"
 		else
t/t9902-completion.sh +16 -0
index 43de868b800..f62a395d827 100755
@@ -2255,6 +2255,22 @@ test_expect_success 'checkout completes ref names' '
 	EOF
 '
 
+test_expect_success 'checkout does not match ref names of a different case' '
+	test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
+		test_completion "git checkout M" <<-\EOF
+		main Z
+		mybranch Z
+		mytag Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#3 lore raw

PATCH 2/2 completion: add case-insensitive match of pseudorefs

In reply to Alison Winters via GitGitGadget

From: Alison Winters <[email protected]>

When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text like "head" to match HEAD and other pseudorefs.

---
 contrib/completion/git-completion.bash | 10 +++++++---
 t/t9902-completion.sh                  | 16 ++++++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)
contrib/completion/git-completion.bash +7 -3
index 8ed96a5b8b6..161327057da 100644
@@ -745,6 +745,7 @@ __git_refs ()
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
+	local umatch="${4-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 	local ignore_case=""
 
@@ -772,6 +773,8 @@ __git_refs ()
 	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
 	then
 		ignore_case="--ignore-case"
+		# use tr instead of ${match,^^} to preserve bash 3.2 compatibility
+		umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")
 	fi
 
 	if [ "$list_refs_from" = path ]; then
@@ -780,6 +783,7 @@ __git_refs ()
 			fer_pfx="$fer_pfx^"
 			cur_=${cur_#^}
 			match=${match#^}
+			umatch=${umatch#^}
 		fi
 		case "$cur_" in
 		refs|refs/*)
@@ -790,7 +794,7 @@ __git_refs ()
 		*)
 			for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
 				case "$i" in
-				$match*)
+				$match*|$umatch*)
 					if [ -e "$dir/$i" ]; then
 						echo "$pfx$i$sfx"
 					fi
@@ -824,7 +828,7 @@ __git_refs ()
 	*)
 		if [ "$list_refs_from" = remote ]; then
 			case "HEAD" in
-			$match*)	echo "${pfx}HEAD$sfx" ;;
+			$match*|$umatch*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 				$ignore_case \
@@ -833,7 +837,7 @@ __git_refs ()
 		else
 			local query_symref
 			case "HEAD" in
-			$match*)	query_symref="HEAD" ;;
+			$match*|$umatch*)	query_symref="HEAD" ;;
 			esac
 			__git ls-remote "$remote" $query_symref \
 				"refs/tags/$match*" "refs/heads/$match*" \
t/t9902-completion.sh +16 -0
index f62a395d827..b4c46567fa4 100755
@@ -2271,6 +2271,22 @@ test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGN
 	)
 '
 
+test_expect_success 'checkout completes pseudo refs' '
+	test_completion "git checkout H" <<-\EOF
+	HEAD Z
+	EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
+		test_completion "git checkout h" <<-\EOF
+		HEAD Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#6 lore raw
In reply to Alison Winters via GitGitGadget

Hi Alison,

Quoted 7 lines · Alison Winters via GitGitGadget

Alison Winters (2):
completion: add optional ignore-case when matching refs
completion: add case-insensitive match of pseudorefs

 contrib/completion/git-completion.bash | 51 ++++++++++++++++++++++++--
 t/t9902-completion.sh                  | 32 ++++++++++++++++
 2 files changed, 80 insertions(+), 3 deletions(-)

It looks reasonable to me, but I'm far from an expert on the completion code ;-).

CC'ing some folks who are going to be more familiar with it than me.

Thanks,
Taylor

#2 lore raw

Re: [PATCH 1/2] completion: add optional ignore-case when matching refs

In reply to Alison Winters via GitGitGadget
Quoted 17 lines · Alison Winters via GitGitGadget

From: Alison Winters <[email protected]>

If GIT_COMPLETION_IGNORE_CASE=1 is set, --ignore-case will be added to git for-each-ref calls so that branches and tags can be matched case insensitively.

---
 contrib/completion/git-completion.bash | 41 ++++++++++++++++++++++++++
 t/t9902-completion.sh                  | 16 ++++++++++
 2 files changed, 57 insertions(+)
contrib/completion/git-completion.bash +0 -0
index ba5c395d2d8..8ed96a5b8b6 100644

contrib/completion/git-completion.bash line 65

Quoted 8 lines
contrib/completion/git-completion.bash +5 -0
@@ -58,6 +58,11 @@
 #
 #     When set to "1" suggest all options, including options which are
 #     typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+#   GIT_COMPLETION_IGNORE_CASE
+#
+#     When set to "1", suggest refs that match case insensitively (e.g.,
+#     completing "FOO" on "git checkout f<TAB>").

I wish the commit message and this comment would be more explicit about only the matching being case insensitive, but the words listed for completion will all have the same case as the files/refs/etc. that are being completed.

I've already started writing a reply along the lines of "does this only work on case-insensitive filesystems?!" before finally realizing that's not how it works...

contrib/completion/git-completion.bash __git_complete_index_file () · line 657

Quoted 12 lines
contrib/completion/git-completion.bash +6 -0
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -644,8 +649,15 @@ __git_complete_index_file ()
 __git_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi

I find these six lines a bit too verbose for what there are doing, especially since the same six lines are added a couple of times. I think it could be shortened to just a single line with the "use alternate value" parameter expansion like this:

    local ignore_case=${GIT_COMPLETION_IGNORE_CASE+--ignore-case}

contrib/completion/git-completion.bash __git_complete_index_file () · line 659

Quoted 2 lines
contrib/completion/git-completion.bash +1 -0
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \

In fact, we could eliminate that new $ignore_case local variable entirely by adding that parameter expansion right here.

Quoted 96 lines
contrib/completion/git-completion.bash +29 -0
 			"refs/heads/$cur_*" "refs/heads/$cur_*/**"
 }
 
@@ -657,8 +669,15 @@ __git_heads ()
 __git_remote_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \
 			"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
 }
 
@@ -667,8 +686,15 @@ __git_remote_heads ()
 __git_tags ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			$ignore_case \
 			"refs/tags/$cur_*" "refs/tags/$cur_*/**"
 }
 
@@ -682,12 +708,19 @@ __git_dwim_remote_heads ()
 {
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+	local ignore_case=""
+
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
 
 	# employ the heuristic used by git checkout and git switch
 	# Try to find a remote branch that cur_es the completion word
 	# but only output if the branch name is unique
 	__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 		--sort="refname:strip=3" \
+		$ignore_case \
 		"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
 	uniq -u
 }
@@ -713,6 +746,7 @@ __git_refs ()
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+	local ignore_case=""
 
 	__git_find_repo_path
 	dir="$__git_repo_path"
@@ -735,6 +769,11 @@ __git_refs ()
 		fi
 	fi
 
+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+	then
+		ignore_case="--ignore-case"
+	fi
+
 	if [ "$list_refs_from" = path ]; then
 		if [[ "$cur_" == ^* ]]; then
 			pfx="$pfx^"
@@ -765,6 +804,7 @@ __git_refs ()
 			;;
 		esac
 		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+			$ignore_case \
 			"${refs[@]}"
 		if [ -n "$track" ]; then
 			__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -787,6 +827,7 @@ __git_refs ()
 			$match*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+				$ignore_case \
 				"refs/remotes/$remote/$match*" \
 				"refs/remotes/$remote/$match*/**"
 		else
t/t9902-completion.sh +0 -0
index 43de868b800..f62a395d827 100755

t/t9902-completion.sh test_expect_success 'checkout completes ref names' ' · line 2264

Quoted 10 lines
t/t9902-completion.sh +7 -0
@@ -2255,6 +2255,22 @@ test_expect_success 'checkout completes ref names' '
 	EOF
 '
 
+test_expect_success 'checkout does not match ref names of a different case' '
+	test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&

I don't think it's necessary to source the completion script here, because the test script's main shell process has already sourced it, and its functions are visible in this test's subshell as well.

(Yeah, there are a few test cases near the end that do (re-)source the completion script, but they do so because they must invalidate the cache variables used by the completion script; this case-insensitive match feature, however, doesn't involve any of those cache variables.)

t/t9902-completion.sh test_expect_success 'checkout completes ref names' ' · line 2265

Quoted 1 line
t/t9902-completion.sh +1 -0
+		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&

There is no need to export this variable, because only a handful of completion helper functions look at it, which are invoked in this same shell process (or perhaps in one of its subshells, but this variable will be visible there are all the same).

Quoted 14 lines
t/t9902-completion.sh +8 -0
+		test_completion "git checkout M" <<-\EOF
+		main Z
+		mybranch Z
+		mytag Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#4 lore raw

Re: [PATCH 2/2] completion: add case-insensitive match of pseudorefs

In reply to Alison Winters via GitGitGadget
Quoted 16 lines · Alison Winters via GitGitGadget

From: Alison Winters <[email protected]>

When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text like "head" to match HEAD and other pseudorefs.

---
 contrib/completion/git-completion.bash | 10 +++++++---
 t/t9902-completion.sh                  | 16 ++++++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)
contrib/completion/git-completion.bash +0 -0
index 8ed96a5b8b6..161327057da 100644

contrib/completion/git-completion.bash __git_refs () · line 748

Quoted 4 lines
contrib/completion/git-completion.bash +1 -0
@@ -745,6 +745,7 @@ __git_refs ()
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
+	local umatch="${4-}"

Why 'umatch' and not 'imatch'?

contrib/completion/git-completion.bash __git_refs () · line 776

Quoted 8 lines
contrib/completion/git-completion.bash +1 -0
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 	local ignore_case=""
 
@@ -772,6 +773,8 @@ __git_refs ()
 	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
 	then
 		ignore_case="--ignore-case"
+		# use tr instead of ${match,^^} to preserve bash 3.2 compatibility

Thank you for keeping compatibility with old versions in mind!

contrib/completion/git-completion.bash __git_refs () · line 777

Quoted 1 line
contrib/completion/git-completion.bash +1 -0
+		umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")

Style nit: we usually don't add a space between the redirection operator and the filename.

Quoted 12 lines
contrib/completion/git-completion.bash +1 -0
 	fi
 
 	if [ "$list_refs_from" = path ]; then
@@ -780,6 +783,7 @@ __git_refs ()
 			fer_pfx="$fer_pfx^"
 			cur_=${cur_#^}
 			match=${match#^}
+			umatch=${umatch#^}
 		fi
 		case "$cur_" in
 		refs|refs/*)

contrib/completion/git-completion.bash __git_refs () · line 797

Quoted 5 lines
contrib/completion/git-completion.bash +1 -1
@@ -790,7 +794,7 @@ __git_refs ()
 		*)
 			for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
 				case "$i" in
-				$match*)
+				$match*|$umatch*)

I find the two patterns here weird. I suppose it works as intended, because with GIT_COMPLETION_IGNORE_CASE being unset both $match and $umatch have the same value, so there is only one pattern after all, but when GIT_COMPLETION_IGNORE_CASE is set then $umatch contains the case insensitive pattern... but I still find it a bit weird :) but I don't know how to make it less weird without introducing code duplication, so it's still better than the alternatives.

Quoted 29 lines
contrib/completion/git-completion.bash +2 -2
 					if [ -e "$dir/$i" ]; then
 						echo "$pfx$i$sfx"
 					fi
@@ -824,7 +828,7 @@ __git_refs ()
 	*)
 		if [ "$list_refs_from" = remote ]; then
 			case "HEAD" in
-			$match*)	echo "${pfx}HEAD$sfx" ;;
+			$match*|$umatch*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 				$ignore_case \
@@ -833,7 +837,7 @@ __git_refs ()
 		else
 			local query_symref
 			case "HEAD" in
-			$match*)	query_symref="HEAD" ;;
+			$match*|$umatch*)	query_symref="HEAD" ;;
 			esac
 			__git ls-remote "$remote" $query_symref \
 				"refs/tags/$match*" "refs/heads/$match*" \
t/t9902-completion.sh +0 -0
index f62a395d827..b4c46567fa4 100755
@@ -2271,6 +2271,22 @@ test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGN
 	)
 '
 

t/t9902-completion.sh test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGN · line 2283

Quoted 10 lines
t/t9902-completion.sh +10 -0
+test_expect_success 'checkout completes pseudo refs' '
+	test_completion "git checkout H" <<-\EOF
+	HEAD Z
+	EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&

The same comment about the unnecessary sourcing and exporting on the previous patch applies here as well.

Quoted 11 lines
t/t9902-completion.sh +6 -0
+		test_completion "git checkout h" <<-\EOF
+		HEAD Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#5 lore raw

Re: [PATCH 2/2] completion: add case-insensitive match of pseudorefs

Quoted 12 lines · SZEDER Gábor
Quoted 11 lines · Alison Winters via GitGitGadget

From: Alison Winters <[email protected]>

When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text like "head" to match HEAD and other pseudorefs.

---
 contrib/completion/git-completion.bash | 10 +++++++---
 t/t9902-completion.sh                  | 16 ++++++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)
Quoted 11 lines

contrib/completion/git-completion.bash __git_refs () · line 748

Quoted 9 lines
contrib/completion/git-completion.bash +1 -0
index 8ed96a5b8b6..161327057da 100644
@@ -745,6 +745,7 @@ __git_refs ()
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
+	local umatch="${4-}"

Why 'umatch' and not 'imatch'?

Gah, because it's all _u_pper case, as can be seen in the next hunk, that's why.

Quoted 13 lines

contrib/completion/git-completion.bash __git_refs () · line 776

Quoted 8 lines
contrib/completion/git-completion.bash +1 -0
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 	local ignore_case=""
 
@@ -772,6 +773,8 @@ __git_refs ()
 	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
 	then
 		ignore_case="--ignore-case"
+		# use tr instead of ${match,^^} to preserve bash 3.2 compatibility

Thank you for keeping compatibility with old versions in mind!

Quoted 1 line
contrib/completion/git-completion.bash +1 -0
+		umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")
#8 lore raw

PATCH v2 1/2 completion: add optional ignore-case when matching refs

In reply to Alison Winters via GitGitGadget

From: Alison Winters <[email protected]>

If GIT_COMPLETION_IGNORE_CASE is set, --ignore-case will be added to git for-each-ref calls so that refs can be matched case insensitively, even when running on case sensitive filesystems.

---
 contrib/completion/git-completion.bash | 12 ++++++++++++
 t/t9902-completion.sh                  | 15 +++++++++++++++
 2 files changed, 27 insertions(+)
contrib/completion/git-completion.bash +12 -0
index ba5c395d2d8..7dcf4b63562 100644
@@ -58,6 +58,12 @@
 #
 #     When set to "1" suggest all options, including options which are
 #     typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+#   GIT_COMPLETION_IGNORE_CASE
+#
+#     When set, uses for-each-ref '--ignore-case' to find refs that match
+#     case insensitively, even on systems with case sensitive file systems
+#     (e.g., completing tag name "FOO" on "git checkout f<TAB>").
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -646,6 +652,7 @@ __git_heads ()
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/heads/$cur_*" "refs/heads/$cur_*/**"
 }
 
@@ -659,6 +666,7 @@ __git_remote_heads ()
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
 }
 
@@ -669,6 +677,7 @@ __git_tags ()
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/tags/$cur_*" "refs/tags/$cur_*/**"
 }
 
@@ -688,6 +697,7 @@ __git_dwim_remote_heads ()
 	# but only output if the branch name is unique
 	__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 		--sort="refname:strip=3" \
+		${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 		"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
 	uniq -u
 }
@@ -765,6 +775,7 @@ __git_refs ()
 			;;
 		esac
 		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"${refs[@]}"
 		if [ -n "$track" ]; then
 			__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -787,6 +798,7 @@ __git_refs ()
 			$match*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+				${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 				"refs/remotes/$remote/$match*" \
 				"refs/remotes/$remote/$match*/**"
 		else
t/t9902-completion.sh +15 -0
index 43de868b800..d89d0a93a2a 100755
@@ -2255,6 +2255,21 @@ test_expect_success 'checkout completes ref names' '
 	EOF
 '
 
+test_expect_success 'checkout does not match ref names of a different case' '
+	test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		GIT_COMPLETION_IGNORE_CASE=1 &&
+		test_completion "git checkout M" <<-\EOF
+		main Z
+		mybranch Z
+		mytag Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#7 lore raw

v2 cover add case insensitivity option to bash completion

In reply to Alison Winters via GitGitGadget

In 3bb16a8bf2 (tag, branch, for-each-ref: add --ignore-case for sorting and filtering, 2016-12-04), support was added for filtering and sorting refs in a case insensitive way. This is a behavior that seems appropriate to enable with shell completion. Many shells provide case insensitive completion as an option, even on filesystems that remain case sensitive.

This patch adds a new variable that, when set, will allow Bash completion to use the --ignore-case option to match refs. Additionally, some basic support is implemented to match pseudorefs like HEAD.

Changes since v1:

* Improved comments and commit messages to clarify behavior on case sensitive filesystems
* Replaced some lengthy if blocks with inline substitution
* As a result of the above change, GIT_COMPLETION_IGNORE_CASE no longer needs to be set to "1" and now just needs to be present in the environment to work
* Removed unnecessary exports in tests

Alison Winters (2):
completion: add optional ignore-case when matching refs
completion: add case-insensitive match of pseudorefs

 contrib/completion/git-completion.bash | 26 +++++++++++++++++++---
 t/t9902-completion.sh                  | 30 ++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 3 deletions(-)

base-commit: a0789512c5a4ae7da935cd2e419f253cb3cb4ce7
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1374%2Falisonatwork%2Fbash-insensitive-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1374/alisonatwork/bash-insensitive-v2
Pull-Request: https://github.com/git/git/pull/1374

Range-diff vs v1:

1: cef9a12b575 ! 1: a261a94877a completion: add optional ignore-case when matching refs

     @@ Metadata
       ## Commit message ##
          completion: add optional ignore-case when matching refs
      
     -    If GIT_COMPLETION_IGNORE_CASE=1 is set, --ignore-case will be added to
     -    git for-each-ref calls so that branches and tags can be matched case
     -    insensitively.
     +    If GIT_COMPLETION_IGNORE_CASE is set, --ignore-case will be added to
     +    git for-each-ref calls so that refs can be matched case insensitively,
     +    even when running on case sensitive filesystems.
      
          Signed-off-by: Alison Winters <[email protected]>
      
     @@ contrib/completion/git-completion.bash
      +#
      +#   GIT_COMPLETION_IGNORE_CASE
      +#
     -+#     When set to "1", suggest refs that match case insensitively (e.g.,
     -+#     completing "FOO" on "git checkout f<TAB>").
     ++#     When set, uses for-each-ref '--ignore-case' to find refs that match
     ++#     case insensitively, even on systems with case sensitive file systems
     ++#     (e.g., completing tag name "FOO" on "git checkout f<TAB>").
       
       case "$COMP_WORDBREAKS" in
       *:*) : great ;;
     -@@ contrib/completion/git-completion.bash: __git_complete_index_file ()
     - __git_heads ()
     - {
     +@@ contrib/completion/git-completion.bash: __git_heads ()
       	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
     -+	local ignore_case=""
     -+
     -+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
     -+	then
     -+		ignore_case="--ignore-case"
     -+	fi
       
       	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
     -+			$ignore_case \
     ++			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       			"refs/heads/$cur_*" "refs/heads/$cur_*/**"
       }
       
     -@@ contrib/completion/git-completion.bash: __git_heads ()
     - __git_remote_heads ()
     - {
     +@@ contrib/completion/git-completion.bash: __git_remote_heads ()
       	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
     -+	local ignore_case=""
     -+
     -+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
     -+	then
     -+		ignore_case="--ignore-case"
     -+	fi
       
       	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
     -+			$ignore_case \
     ++			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       			"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
       }
       
     -@@ contrib/completion/git-completion.bash: __git_remote_heads ()
     - __git_tags ()
     - {
     +@@ contrib/completion/git-completion.bash: __git_tags ()
       	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
     -+	local ignore_case=""
     -+
     -+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
     -+	then
     -+		ignore_case="--ignore-case"
     -+	fi
       
       	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
     -+			$ignore_case \
     ++			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       			"refs/tags/$cur_*" "refs/tags/$cur_*/**"
       }
       
      @@ contrib/completion/git-completion.bash: __git_dwim_remote_heads ()
     - {
     - 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
     - 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
     -+	local ignore_case=""
     -+
     -+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
     -+	then
     -+		ignore_case="--ignore-case"
     -+	fi
     - 
     - 	# employ the heuristic used by git checkout and git switch
     - 	# Try to find a remote branch that cur_es the completion word
       	# but only output if the branch name is unique
       	__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
       		--sort="refname:strip=3" \
     -+		$ignore_case \
     ++		${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       		"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
       	uniq -u
       }
     -@@ contrib/completion/git-completion.bash: __git_refs ()
     - 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
     - 	local match="${4-}"
     - 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
     -+	local ignore_case=""
     - 
     - 	__git_find_repo_path
     - 	dir="$__git_repo_path"
     -@@ contrib/completion/git-completion.bash: __git_refs ()
     - 		fi
     - 	fi
     - 
     -+	if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
     -+	then
     -+		ignore_case="--ignore-case"
     -+	fi
     -+
     - 	if [ "$list_refs_from" = path ]; then
     - 		if [[ "$cur_" == ^* ]]; then
     - 			pfx="$pfx^"
      @@ contrib/completion/git-completion.bash: __git_refs ()
       			;;
       		esac
       		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
     -+			$ignore_case \
     ++			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       			"${refs[@]}"
       		if [ -n "$track" ]; then
       			__git_dwim_remote_heads "$pfx" "$match" "$sfx"
     @@ contrib/completion/git-completion.bash: __git_refs ()
       			$match*)	echo "${pfx}HEAD$sfx" ;;
       			esac
       			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
     -+				$ignore_case \
     ++				${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
       				"refs/remotes/$remote/$match*" \
       				"refs/remotes/$remote/$match*/**"
       		else
     @@ t/t9902-completion.sh: test_expect_success 'checkout completes ref names' '
      +
      +test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
      +	(
     -+		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
     -+		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
     ++		GIT_COMPLETION_IGNORE_CASE=1 &&
      +		test_completion "git checkout M" <<-\EOF
      +		main Z
      +		mybranch Z

2: c455e855395 ! 2: 480f6554c93 completion: add case-insensitive match of pseudorefs
@@ Metadata
## Commit message ##
completion: add case-insensitive match of pseudorefs

- When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text
- like "head" to match HEAD and other pseudorefs.
+ When GIT_COMPLETION_IGNORE_CASE is set, also allow lowercase completion
+ text like "head" to match uppercase HEAD and other pseudorefs.

@@ contrib/completion/git-completion.bash: __git_refs ()
local match="${4-}"
+ local umatch="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
- local ignore_case=""

+ __git_find_repo_path
@@ contrib/completion/git-completion.bash: __git_refs ()
- if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
- then
- ignore_case="--ignore-case"
-+ # use tr instead of ${match,^^} to preserve bash 3.2 compatibility
-+ umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")
+ fi
fi

++ if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
++ then
++ # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
++ umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
++ fi
++
if [ "$list_refs_from" = path ]; then
-@@ contrib/completion/git-completion.bash: __git_refs ()
+ if [[ "$cur_" == ^* ]]; then
+ pfx="$pfx^"
fer_pfx="$fer_pfx^"
cur_=${cur_#^}
match=${match#^}
@@ contrib/completion/git-completion.bash: __git_refs ()
+ $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
- $ignore_case \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
@@ contrib/completion/git-completion.bash: __git_refs ()
else
local query_symref
@@ t/t9902-completion.sh: test_expect_success 'checkout matches case insensitively
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+ (
-+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
-+ GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
++ GIT_COMPLETION_IGNORE_CASE=1 &&
+ test_completion "git checkout h" <<-\EOF
+ HEAD Z
+ EOF

Signature · 1 line
gitgitgadget
#9 lore raw

PATCH v2 2/2 completion: add case-insensitive match of pseudorefs

From: Alison Winters <[email protected]>

When GIT_COMPLETION_IGNORE_CASE is set, also allow lowercase completion text like "head" to match uppercase HEAD and other pseudorefs.

---
 contrib/completion/git-completion.bash | 14 +++++++++++---
 t/t9902-completion.sh                  | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
contrib/completion/git-completion.bash +11 -3
index 7dcf4b63562..dc95c34cc85 100644
@@ -722,6 +722,7 @@ __git_refs ()
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
+	local umatch="${4-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 
 	__git_find_repo_path
@@ -745,12 +746,19 @@ __git_refs ()
 		fi
 	fi
 
+	if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
+	then
+		# uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
+		umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
+	fi
+
 	if [ "$list_refs_from" = path ]; then
 		if [[ "$cur_" == ^* ]]; then
 			pfx="$pfx^"
 			fer_pfx="$fer_pfx^"
 			cur_=${cur_#^}
 			match=${match#^}
+			umatch=${umatch#^}
 		fi
 		case "$cur_" in
 		refs|refs/*)
@@ -761,7 +769,7 @@ __git_refs ()
 		*)
 			for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
 				case "$i" in
-				$match*)
+				$match*|$umatch*)
 					if [ -e "$dir/$i" ]; then
 						echo "$pfx$i$sfx"
 					fi
@@ -795,7 +803,7 @@ __git_refs ()
 	*)
 		if [ "$list_refs_from" = remote ]; then
 			case "HEAD" in
-			$match*)	echo "${pfx}HEAD$sfx" ;;
+			$match*|$umatch*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 				${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
@@ -804,7 +812,7 @@ __git_refs ()
 		else
 			local query_symref
 			case "HEAD" in
-			$match*)	query_symref="HEAD" ;;
+			$match*|$umatch*)	query_symref="HEAD" ;;
 			esac
 			__git ls-remote "$remote" $query_symref \
 				"refs/tags/$match*" "refs/heads/$match*" \
t/t9902-completion.sh +15 -0
index d89d0a93a2a..d6c0478d98b 100755
@@ -2270,6 +2270,21 @@ test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGN
 	)
 '
 
+test_expect_success 'checkout completes pseudo refs' '
+	test_completion "git checkout H" <<-\EOF
+	HEAD Z
+	EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		GIT_COMPLETION_IGNORE_CASE=1 &&
+		test_completion "git checkout h" <<-\EOF
+		HEAD Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
Signature · 1 line
gitgitgadget
#10 lore raw
In reply to Alison Winters via GitGitGadget
Quoted 9 lines · Alison Winters via GitGitGadget

In 3bb16a8bf2 (tag, branch, for-each-ref: add --ignore-case for sorting and filtering, 2016-12-04), support was added for filtering and sorting refs in a case insensitive way. This is a behavior that seems appropriate to enable with shell completion. Many shells provide case insensitive completion as an option, even on filesystems that remain case sensitive.

This patch adds a new variable that, when set, will allow Bash completion to use the --ignore-case option to match refs. Additionally, some basic support is implemented to match pseudorefs like HEAD.

I did not try to figure out the reason but the topic with its tests seem to break in 'seen' the linux-cmake-ctest CI job.

https://github.com/git/git/actions/runs/3570230611/jobs/6001013549

but the same test does not break under usual "make test".

Can people who are interested in the cmake-ctest stuff take a look?

It is tempting to eject the ab/cmake-nix-and-ci topic that is already in 'next', under the theory that what that topic does to the tests "works" for some tests but not for others, and this topic is an unfortunate collateral damage whose tests weren't something the other topic supports well. If the cmake-ctest stuff is in such a shape, then it may have been a bit premature to merge it down.

Thanks.

#11 lore raw
Quoted 6 lines · Junio C Hamano

I did not try to figure out the reason but the topic with its tests seem to break in 'seen' the linux-cmake-ctest CI job.

https://github.com/git/git/actions/runs/3570230611/jobs/6001013549

but the same test does not break under usual "make test".

I cannot speak for how the changes of the ab/cmake-nix-and-ci impact the aw/complete-case-insensitive branch, but the failure seems to be pointing to a test that I have since changed in the v2 patch, on the suggestion of Szeder Gabor. The variable is no longer exported and the script is no longer sourced a second time. I don't know if those v2 changes would change the results of this test, but they might be a starting point for the other people CC:ed here to consider.

Alison

#12 lore raw
Quoted 8 lines · Alison Winters
Quoted 6 lines · Junio C Hamano

I did not try to figure out the reason but the topic with its tests seem to break in 'seen' the linux-cmake-ctest CI job.

https://github.com/git/git/actions/runs/3570230611/jobs/6001013549

but the same test does not break under usual "make test".

Quoted 7 lines

I cannot speak for how the changes of the ab/cmake-nix-and-ci impact the aw/complete-case-insensitive branch, but the failure seems to be pointing to a test that I have since changed in the v2 patch, on the suggestion of Szeder Gabor. The variable is no longer exported and the script is no longer sourced a second time. I don't know if those v2 changes would change the results of this test, but they might be a starting point for the other people CC:ed here to consider.

The breakage is due to a semantic conflict between the two, which is solved thusly:

	diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
	index d45d820da28..2aa128075ca 100755
	--- a/t/t9902-completion.sh
	+++ b/t/t9902-completion.sh
	@@ -2261,7 +2261,7 @@ test_expect_success 'checkout does not match ref names of a different case' '
	 
	 test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
	 	(
	-		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
	+		. "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" &&
	 		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
	 		test_completion "git checkout M" <<-\EOF
	 		main Z
	@@ -2279,7 +2279,7 @@ test_expect_success 'checkout completes pseudo refs' '
	 
	 test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
	 	(
	-		. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
	+		. "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" &&
	 		GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
	 		test_completion "git checkout h" <<-\EOF
	 		HEAD Z

Junio: I don't think this warrants kicking out the cmake topic. This sort of problem is just going to occur while something like that is in-flight, or Alison would have otherwise presumably seen it as a CI failure if based off "master".

With hindsight I could have made e74e51a9154 (cmake & test-lib.sh: add a $GIT_SOURCE_DIR variable, 2022-11-03) do the migration in two phases, but I didn't expect another topic to rely on the relatively obscure bits that were being copied to the $GIT_BUILD_DIR, we weren't exactly drowning in git-completion.bash patches...

#13 lore raw
Quoted 37 lines · Ævar Arnfjörð Bjarmason
Quoted 8 lines · Alison Winters
Quoted 6 lines · Junio C Hamano

I did not try to figure out the reason but the topic with its tests seem to break in 'seen' the linux-cmake-ctest CI job.

https://github.com/git/git/actions/runs/3570230611/jobs/6001013549

but the same test does not break under usual "make test".

Quoted 7 lines

I cannot speak for how the changes of the ab/cmake-nix-and-ci impact the aw/complete-case-insensitive branch, but the failure seems to be pointing to a test that I have since changed in the v2 patch, on the suggestion of Szeder Gabor. The variable is no longer exported and the script is no longer sourced a second time. I don't know if those v2 changes would change the results of this test, but they might be a starting point for the other people CC:ed here to consider.

The breakage is due to a semantic conflict between the two, which is solved thusly:

    diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
    index d45d820da28..2aa128075ca 100755
    --- a/t/t9902-completion.sh
    +++ b/t/t9902-completion.sh
    @@ -2261,7 +2261,7 @@ test_expect_success 'checkout does not match ref names of a different case' '

     test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' ' (
    -        . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
    +        . "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" && GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE && test_completion "git checkout M" <<-\EOF
             main Z
    @@ -2279,7 +2279,7 @@ test_expect_success 'checkout completes pseudo refs' '

Quoted 7 lines

     test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' ' (
    -        . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
    +        . "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" && GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE && test_completion "git checkout h" <<-\EOF
             HEAD Z

In this case, I think the easiest solution will be to move the aw/complete-case-insensitive branch forward to the v2 patch (posted to the list @ 2022-11-21  0:26 UTC), which no longer includes this line.

Alison

#14 lore raw
Quoted 3 lines · Alison Winters

In this case, I think the easiest solution will be to move the aw/complete-case-insensitive branch forward to the v2 patch (posted to the list @ 2022-11-21  0:26 UTC), which no longer includes this line.

Indeed. With <[email protected]> merged on top of a known-good subset of 'seen', cmake-ctest thing did not fail.

https://github.com/git/git/actions/runs/3579752650/jobs/6021251201

Thanks.

P.S. Ignore the osx-gcc job that was cancelled in the same run; as this is not the only topic I have to deal with, I submitted a trial merge into 'seen' of another topic after seeing cmake-ctest job finish, but because of recent CI change to cancel an earlier job when a new job is started, it got auto-cancelled (which is mostly a good thing for regular developer workflow, but not for me X-<)