threads / patch / 58751

patch, 2 partsadd case insensitivity option to bash completion

Subject: [PATCH 0/2] add case insensitivity option to bash completion

## tl;dr

15 messages between Nov 5, 2022 and Nov 30, 2022. Diffs are folded; open one to read it.

replies: 14people: 5as markdown or json

Alison Winters via GitGitGadget· Nov 5, 2022, 17:28 UTC · lore

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
-- 
gitgitgadget
Alison Winters via GitGitGadget· Nov 5, 2022, 17:28 UTC · re: Alison Winters via GitGitGadget · lore

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

From: Alison Winters <alisonatwork@outlook.com>

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.

Signed-off-by: Alison Winters <alisonatwork@outlook.com>
---
 contrib/completion/git-completion.bash | 41 ++++++++++++++++++++++++++
 t/t9902-completion.sh                  | 16 ++++++++++
 2 files changed, 57 insertions(+)
Show changes to 2 files +57 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d8..8ed96a5b8b6 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 43de868b800..f62a395d827 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -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
-- 
gitgitgadget
SZEDER Gábor· Nov 20, 2022, 20:24 UTC · re: Alison Winters via GitGitGadget · lore

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

On Sat, Nov 05, 2022 at 05:28:34PM +0000, Alison Winters via GitGitGadget wrote:
Show 25 quoted lines
> From: Alison Winters <alisonatwork@outlook.com>
> 
> 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.
> 
> Signed-off-by: Alison Winters <alisonatwork@outlook.com>
> ---
>  contrib/completion/git-completion.bash | 41 ++++++++++++++++++++++++++
>  t/t9902-completion.sh                  | 16 ++++++++++
>  2 files changed, 57 insertions(+)
> 
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index ba5c395d2d8..8ed96a5b8b6 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -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...

Show 12 quoted lines
>  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}
>  	__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.

Show 106 quoted lines
>  			"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
> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
> index 43de868b800..f62a395d827 100755
> --- a/t/t9902-completion.sh
> +++ b/t/t9902-completion.sh
> @@ -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.)

> +		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).

Show 14 quoted lines
> +		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
> -- 
> gitgitgadget
> 
Alison Winters via GitGitGadget· Nov 5, 2022, 17:28 UTC · re: Alison Winters via GitGitGadget · lore

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

From: Alison Winters <alisonatwork@outlook.com>

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

Signed-off-by: Alison Winters <alisonatwork@outlook.com>
---
 contrib/completion/git-completion.bash | 10 +++++++---
 t/t9902-completion.sh                  | 16 ++++++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)
Show changes to 2 files +23 −3

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 8ed96a5b8b6..161327057da 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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*" \
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index f62a395d827..b4c46567fa4 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -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
-- 
gitgitgadget
SZEDER Gábor· Nov 20, 2022, 20:42 UTC · re: Alison Winters via GitGitGadget · lore

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

On Sat, Nov 05, 2022 at 05:28:35PM +0000, Alison Winters via GitGitGadget wrote:
Show 20 quoted lines
> From: Alison Winters <alisonatwork@outlook.com>
> 
> When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text
> like "head" to match HEAD and other pseudorefs.
> 
> Signed-off-by: Alison Winters <alisonatwork@outlook.com>
> ---
>  contrib/completion/git-completion.bash | 10 +++++++---
>  t/t9902-completion.sh                  | 16 ++++++++++++++++
>  2 files changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 8ed96a5b8b6..161327057da 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -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'?
Show 8 quoted lines
>  	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!
> +		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.

Show 17 quoted lines
>  	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*)

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.

Show 39 quoted lines
>  					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*" \
> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
> index f62a395d827..b4c46567fa4 100755
> --- a/t/t9902-completion.sh
> +++ b/t/t9902-completion.sh
> @@ -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 &&

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

Show 11 quoted lines
> +		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
> -- 
> gitgitgadget
SZEDER Gábor· Nov 20, 2022, 20:46 UTC · re: SZEDER Gábor · lore

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

On Sun, Nov 20, 2022 at 09:42:32PM +0100, SZEDER Gábor wrote:
Show 23 quoted lines
> On Sat, Nov 05, 2022 at 05:28:35PM +0000, Alison Winters via GitGitGadget wrote:
> > From: Alison Winters <alisonatwork@outlook.com>
> > 
> > When GIT_COMPLETION_IGNORE_CASE=1, also allow lowercase completion text
> > like "head" to match HEAD and other pseudorefs.
> > 
> > Signed-off-by: Alison Winters <alisonatwork@outlook.com>
> > ---
> >  contrib/completion/git-completion.bash | 10 +++++++---
> >  t/t9902-completion.sh                  | 16 ++++++++++++++++
> >  2 files changed, 23 insertions(+), 3 deletions(-)
> > 
> > diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> > index 8ed96a5b8b6..161327057da 100644
> > --- a/contrib/completion/git-completion.bash
> > +++ b/contrib/completion/git-completion.bash
> > @@ -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.

Show 13 quoted lines
> >  	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!
> 
> > +		umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")
> 
Taylor Blau· Nov 8, 2022, 03:00 UTC · re: Alison Winters via GitGitGadget · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

Hi Alison,
On Sat, Nov 05, 2022 at 05:28:33PM +0000, Alison Winters via GitGitGadget wrote:
Show 7 quoted lines
> 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

Alison Winters via GitGitGadget· Nov 21, 2022, 00:26 UTC · re: Alison Winters via GitGitGadget · lore

[PATCH v2 0/2] 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.

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 <alisonatwork@outlook.com>
      
     @@ 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.
      
          Signed-off-by: Alison Winters <alisonatwork@outlook.com>
      
     @@ 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
-- 
gitgitgadget
Alison Winters via GitGitGadget· Nov 21, 2022, 00:26 UTC · re: Alison Winters via GitGitGadget · lore

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

From: Alison Winters <alisonatwork@outlook.com>

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 <alisonatwork@outlook.com>
---
 contrib/completion/git-completion.bash | 12 ++++++++++++
 t/t9902-completion.sh                  | 15 +++++++++++++++
 2 files changed, 27 insertions(+)
Show changes to 2 files +27 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d8..7dcf4b63562 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 43de868b800..d89d0a93a2a 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -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
-- 
gitgitgadget
Alison Winters via GitGitGadget· Nov 21, 2022, 00:26 UTC · re: Alison Winters via GitGitGadget · lore

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

From: Alison Winters <alisonatwork@outlook.com>

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

Signed-off-by: Alison Winters <alisonatwork@outlook.com>
---
 contrib/completion/git-completion.bash | 14 +++++++++++---
 t/t9902-completion.sh                  | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
Show changes to 2 files +26 −3

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 7dcf4b63562..dc95c34cc85 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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*" \
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index d89d0a93a2a..d6c0478d98b 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -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
-- 
gitgitgadget
Junio C Hamano· Nov 29, 2022, 02:38 UTC · re: Alison Winters via GitGitGadget · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

"Alison Winters via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 9 quoted lines
> 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.
Alison Winters· Nov 29, 2022, 15:56 UTC · re: Junio C Hamano · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

On 2022-11-29 10:38, Junio C Hamano wrote:
 > 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
Ævar Arnfjörð Bjarmason· Nov 29, 2022, 17:40 UTC · re: Alison Winters · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

On Tue, Nov 29 2022, Alison Winters wrote:
Show 15 quoted lines
> On 2022-11-29 10:38, Junio C Hamano wrote:
>> 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.
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...

Alison Winters· Nov 30, 2022, 00:37 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

On 2022-11-30 01:40, Ævar Arnfjörð Bjarmason wrote:
 >
 > On Tue, Nov 29 2022, Alison Winters wrote:
 >
 >> On 2022-11-29 10:38, Junio C Hamano wrote:
 >>> 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.
 >
 > 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

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
Junio C Hamano· Nov 30, 2022, 03:08 UTC · re: Alison Winters · lore

Re: [PATCH 0/2] add case insensitivity option to bash completion

Alison Winters <alisonatwork@outlook.com> writes:
> 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 <pull.1374.v2.git.git.1668990419.gitgitgadget@gmail.com> 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-<)

← back to recent threads