add case insensitivity option to bash completion
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
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
@@ -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
@@ -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
PATCH 2/2 completion: add case-insensitive match of pseudorefs
In reply to Alison Winters via GitGitGadgetFrom: 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
@@ -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
@@ -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
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 pseudorefscontrib/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
Re: [PATCH 1/2] completion: add optional ignore-case when matching refs
In reply to Alison Winters via GitGitGadgetQuoted 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.
Signed-off-by Alison Winters <[email protected]>--- contrib/completion/git-completion.bash | 41 ++++++++++++++++++++++++++ t/t9902-completion.sh | 16 ++++++++++ 2 files changed, 57 insertions(+)contrib/completion/git-completion.bash +0
-0
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
-0case "$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*/**" elset/t9902-completion.sh +0
-0
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 ZSignature · 1 line
gitgitgadget
Re: [PATCH 2/2] completion: add case-insensitive match of pseudorefs
In reply to Alison Winters via GitGitGadgetQuoted 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.
Signed-off-by Alison Winters <[email protected]>--- 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
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
-0local 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
-0fi 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
-2if [ -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@@ -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 ZSignature · 1 line
gitgitgadget
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.
Signed-off-by Alison Winters <[email protected]>--- 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@@ -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
-0local 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 compatibilityThank 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")
PATCH v2 1/2 completion: add optional ignore-case when matching refs
In reply to Alison Winters via GitGitGadgetFrom: 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
@@ -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
@@ -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
v2 cover add case insensitivity option to bash completion
In reply to Alison Winters via GitGitGadgetIn 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
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
@@ -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
@@ -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
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.
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
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...
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.shb/t/t9902-completion.sh
indexd45d820da28..2aa128075ca100755
---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 withGIT_COMPLETION_IGNORE_CASE' ' (
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ . "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" && GIT_COMPLETION_IGNORE_CASE=1 && exportGIT_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 withGIT_COMPLETION_IGNORE_CASE' ' (
- . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ . "$GIT_SOURCE_DIR/contrib/completion/git-completion.bash" && GIT_COMPLETION_IGNORE_CASE=1 && exportGIT_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
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-<)