Re: [PATCH v2 2/2] completion: fix bugs with slashes in remote names
- From
David Mandelberg <david@mandelberg.org>
- Date
- Mar 6, 2025, 17:12 UTC
- Message-ID
- <7f00dc07-5905-4571-84f4-e50c39867818@mandelberg.org>
- In-Reply-To
- <2bed28ca-b106-474d-9bac-db377bc51949@gmail.com>
Op 2025-03-06 om 11:35 schreef Phillip Wood:
Show 76 quoted lines
> Hi David
>
> On 05/03/2025 20:50, David Mandelberg wrote:
>> David Mandelberg schreef op 2025-03-04 19:09:
>>> Previously, some calls to for-each-ref passed fixed numbers of path
>>> components to strip from refs, assuming that remote names had no slashes
>>> in them. This made completions like:
>>>
>>> git push github/dseomn :com<Tab>
>>>
>>> Result in:
>>>
>>> git push github/dseomn :dseomn/completion-remote-slash
>>>
>>> With this patch, it instead results in:
>>>
>>> git push github/dseomn :completion-remote-slash
>>>
>>> Signed-off-by: David Mandelberg <david@mandelberg.org>
>>> ---
>>> contrib/completion/git-completion.bash | 38 +++++-
>>> t/t9902-completion.sh | 180 ++++++++++++++++++++++---
>>> 2 files changed, 189 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/contrib/completion/git-completion.bash b/contrib/
>>> completion/git-completion.bash
>>> index 5fdc71208e..450fabc901 100644
>>> --- a/contrib/completion/git-completion.bash
>>> +++ b/contrib/completion/git-completion.bash
>>> @@ -790,16 +790,39 @@ __git_tags ()
>>> __git_dwim_remote_heads ()
>>> {
>>> local pfx="${1-}" cur_="${2-}" sfx="${3-}"
>>> - local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format
>>> specifiers
>>> # 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" \
>>> - ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
>>> - "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
>>> - uniq -u
>>> + local awk_script='
>>> + function casemap(s) {
>>> + if (ENVIRON["IGNORE_CASE"])
>>> + return tolower(s)
>>> + else
>>> + return s
>>> + }
>>> + BEGIN {
>>> + split(ENVIRON["REMOTES"], remotes, /\n/)
>>> + for (i in remotes)
>>> + remotes[i] = "refs/remotes/" casemap(remotes[i])
>>> + cur_ = casemap(ENVIRON["CUR_"])
>>> + }
>>> + {
>>> + ref_case = casemap($0)
>>> + for (i in remotes) {
>>> + if (index(ref_case, remotes[i] "/" cur_) == 1) {
>>> + branch = substr($0, length(remotes[i] "/") + 1)
>>> + print ENVIRON["PFX"] branch ENVIRON["SFX"]
>>> + break
>>> + }
>>> + }
>>> + }
>>> + '
>>> + __git for-each-ref --format='%(refname)' |
>>> + PFX="$pfx" SFX="$sfx" CUR_="$cur_" \
>>> + IGNORE_CASE=${GIT_COMPLETION_IGNORE_CASE+1} \
>>> + REMOTES="$(__git_remotes | sort -r)" awk "$awk_script" |
>>> + sort | uniq -u
>
> I wonder if we can use "sort -u" here and drop uniq. It isn't quite the
> same as it will remove entries that are equal according to the current
> locale but I don't think that should matter.That's what I thought when I first saw that, but `uniq -u` removes duplicates:
$ printf 'a\nb\na\n' | sort | uniq -u b $ printf 'a\nb\na\n' | sort -u a b >> I realized that this sends refs to awk that it doesn't need to. I'll
Show 23 quoted lines
>> apply this diff to the next version of this patch:
>
> With that tweak this looks good. If there are no glob characters then
> "git for-each-ref" does a prefix match so strictly speaking you don't
> need the '**' but I don't think it matters in practice. I had one
> thought below but if you don't feel like spending more that on this I
> think what you have here is fine.
>
> The filtering is O(number of remote refs * number of remotes). If we
> could sort the list of remotes and remote refs in the same order then we
> can reduce this to O(number of remote refs + number of remotes) by doing
> (in pseudo code)
>
> for ($ref in $remote_refs) {
> while (!starts_with($ref, "refs/remotes/$remote[$i]"))
> $i++;
> if (starts_with($ref, "refs/remotes/$remote[$i]/$cur_)
> print $ref;
> }
>
> I think we can get "git for-each-ref --sort=-refname" and "sort -r" to
> agree on a sorting order by setting LC_COLLATE=C, otherwise "sort" will
> sort according the the current locale whereas git sorts by bytes.On my desktop, a similar-ish loop takes about 0.1s with 1000*1000 iterations. 1000 remote branches seems plausible but on the high side to me, and 1000 remotes seems very high to me. Do you still think it's worth optimizing? I do think your solution would work, but I think it would take a decent amount of testing to avoid the collation issues you mentioned, and off-by-one errors and the like. So I'd rather not do it unless there's a practical performance advantage, not just theoretical. (Which is what I thought about minimizing forks too, before I learned that it was a practical issue.)
$ time seq 1 1000 | LONG="$(seq 1 1000)" awk 'BEGIN { split(ENVIRON["LONG"], long, /\n/); } { for (i in long) { if ($0 == long[i]) { print; } } }' > /dev/null
real 0m0,092s user 0m0,067s sys 0m0,028s
Show 703 quoted lines
> Best Wishes
>
> Phillip
>
>> diff --git a/contrib/completion/git-completion.bash b/contrib/
>> completion/git-completion.bash
>> index 450fabc901..c9d014070c 100644
>> --- a/contrib/completion/git-completion.bash
>> +++ b/contrib/completion/git-completion.bash
>> @@ -818,7 +818,7 @@ __git_dwim_remote_heads ()
>> }
>> }
>> '
>> - __git for-each-ref --format='%(refname)' |
>> + __git for-each-ref --format='%(refname)' 'refs/remotes/**' |
>> PFX="$pfx" SFX="$sfx" CUR_="$cur_" \
>> IGNORE_CASE=${GIT_COMPLETION_IGNORE_CASE+1} \
>> REMOTES="$(__git_remotes | sort -r)" awk
>> "$awk_script" |
>>
>>> }
>>> # Lists refs from the local (by default) or from a remote repository.
>>> @@ -905,7 +928,8 @@ __git_refs ()
>>> case "HEAD" in
>>> $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
>>> esac
>>> - __git for-each-ref --
>>> format="$fer_pfx%(refname:strip=3)$sfx" \
>>> + local strip="$(__git_count_path_components "refs/
>>> remotes/$remote")"
>>> + __git for-each-ref --
>>> format="$fer_pfx%(refname:strip=$strip)$sfx" \
>>> ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
>>> "refs/remotes/$remote/$match*" \
>>> "refs/remotes/$remote/$match*/**"
>>> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
>>> index 015289c776..343b8cd191 100755
>>> --- a/t/t9902-completion.sh
>>> +++ b/t/t9902-completion.sh
>>> @@ -149,7 +149,8 @@ fi
>>> test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
>>> mkdir -p subdir/subsubdir &&
>>> mkdir -p non-repo &&
>>> - git init -b main otherrepo
>>> + git init -b main otherrepo &&
>>> + git init -b main slashrepo
>>> '
>>> test_expect_success '__git_find_repo_path - from command line
>>> (through $__git_dir)' '
>>> @@ -674,6 +675,13 @@ test_expect_success 'setup for ref completion' '
>>> ) &&
>>> git remote add other "$ROOT/otherrepo/.git" &&
>>> git fetch --no-tags other &&
>>> + (
>>> + cd slashrepo &&
>>> + git commit --allow-empty -m initial &&
>>> + git branch -m main branch/with/slash
>>> + ) &&
>>> + git remote add remote/with/slash "$ROOT/slashrepo/.git" &&
>>> + git fetch --no-tags remote/with/slash &&
>>> rm -f .git/FETCH_HEAD &&
>>> git init thirdrepo
>>> '
>>> @@ -686,6 +694,8 @@ test_expect_success '__git_refs - simple' '
>>> other/HEAD
>>> other/branch-in-other
>>> other/main-in-other
>>> + remote/with/slash/HEAD
>>> + remote/with/slash/branch/with/slash
>>> matching-tag
>>> EOF
>>> (
>>> @@ -702,6 +712,8 @@ test_expect_success '__git_refs - full refs' '
>>> refs/remotes/other/HEAD
>>> refs/remotes/other/branch-in-other
>>> refs/remotes/other/main-in-other
>>> + refs/remotes/remote/with/slash/HEAD
>>> + refs/remotes/remote/with/slash/branch/with/slash
>>> refs/tags/matching-tag
>>> EOF
>>> (
>>> @@ -767,6 +779,19 @@ test_expect_success '__git_refs - configured
>>> remote' '
>>> test_cmp expected "$actual"
>>> '
>>> +test_expect_success '__git_refs - configured remote - with slash' '
>>> + cat >expected <<-EOF &&
>>> + HEAD
>>> + HEAD
>>> + branch/with/slash
>>> + EOF
>>> + (
>>> + cur= &&
>>> + __git_refs remote/with/slash >"$actual"
>>> + ) &&
>>> + test_cmp expected "$actual"
>>> +'
>>> +
>>> test_expect_success '__git_refs - configured remote - full refs' '
>>> cat >expected <<-EOF &&
>>> HEAD
>>> @@ -909,17 +934,19 @@ test_expect_success '__git_refs - unique remote
>>> branches for git checkout DWIMer
>>> other/ambiguous
>>> other/branch-in-other
>>> other/main-in-other
>>> - remote/ambiguous
>>> - remote/branch-in-remote
>>> + remote/with/slash/HEAD
>>> + remote/with/slash/ambiguous
>>> + remote/with/slash/branch-in-remote
>>> + remote/with/slash/branch/with/slash
>>> matching-tag
>>> - HEAD
>>> branch-in-other
>>> branch-in-remote
>>> + branch/with/slash
>>> main-in-other
>>> EOF
>>> for remote_ref in refs/remotes/other/ambiguous \
>>> - refs/remotes/remote/ambiguous \
>>> - refs/remotes/remote/branch-in-remote
>>> + refs/remotes/remote/with/slash/ambiguous \
>>> + refs/remotes/remote/with/slash/branch-in-remote
>>> do
>>> git update-ref $remote_ref main &&
>>> test_when_finished "git update-ref -d $remote_ref" || return 1
>>> @@ -939,6 +966,8 @@ test_expect_success '__git_refs - after --opt=' '
>>> other/HEAD
>>> other/branch-in-other
>>> other/main-in-other
>>> + remote/with/slash/HEAD
>>> + remote/with/slash/branch/with/slash
>>> matching-tag
>>> EOF
>>> (
>>> @@ -955,6 +984,8 @@ test_expect_success '__git_refs - after --opt= -
>>> full refs' '
>>> refs/remotes/other/HEAD
>>> refs/remotes/other/branch-in-other
>>> refs/remotes/other/main-in-other
>>> + refs/remotes/remote/with/slash/HEAD
>>> + refs/remotes/remote/with/slash/branch/with/slash
>>> refs/tags/matching-tag
>>> EOF
>>> (
>>> @@ -972,6 +1003,8 @@ test_expect_success '__git refs - excluding refs' '
>>> ^other/HEAD
>>> ^other/branch-in-other
>>> ^other/main-in-other
>>> + ^remote/with/slash/HEAD
>>> + ^remote/with/slash/branch/with/slash
>>> ^matching-tag
>>> EOF
>>> (
>>> @@ -988,6 +1021,8 @@ test_expect_success '__git refs - excluding full
>>> refs' '
>>> ^refs/remotes/other/HEAD
>>> ^refs/remotes/other/branch-in-other
>>> ^refs/remotes/other/main-in-other
>>> + ^refs/remotes/remote/with/slash/HEAD
>>> + ^refs/remotes/remote/with/slash/branch/with/slash
>>> ^refs/tags/matching-tag
>>> EOF
>>> (
>>> @@ -1015,6 +1050,8 @@ test_expect_success '__git_refs - do not filter
>>> refs unless told so' '
>>> other/branch-in-other
>>> other/main-in-other
>>> other/matching/branch-in-other
>>> + remote/with/slash/HEAD
>>> + remote/with/slash/branch/with/slash
>>> matching-tag
>>> matching/tag
>>> EOF
>>> @@ -1135,6 +1172,8 @@ test_expect_success '__git_complete_refs -
>>> simple' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> matching-tag Z
>>> EOF
>>> (
>>> @@ -1173,6 +1212,20 @@ test_expect_success '__git_complete_refs -
>>> remote' '
>>> test_cmp expected out
>>> '
>>> +test_expect_success '__git_complete_refs - remote - with slash' '
>>> + sed -e "s/Z$//" >expected <<-EOF &&
>>> + HEAD Z
>>> + HEAD Z
>>> + branch/with/slash Z
>>> + EOF
>>> + (
>>> + cur= &&
>>> + __git_complete_refs --remote=remote/with/slash &&
>>> + print_comp
>>> + ) &&
>>> + test_cmp expected out
>>> +'
>>> +
>>> test_expect_success '__git_complete_refs - track' '
>>> sed -e "s/Z$//" >expected <<-EOF &&
>>> HEAD Z
>>> @@ -1181,9 +1234,11 @@ test_expect_success '__git_complete_refs -
>>> track' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> matching-tag Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main-in-other Z
>>> EOF
>>> (
>>> @@ -1228,6 +1283,8 @@ test_expect_success '__git_complete_refs -
>>> suffix' '
>>> other/HEAD.
>>> other/branch-in-other.
>>> other/main-in-other.
>>> + remote/with/slash/HEAD.
>>> + remote/with/slash/branch/with/slash.
>>> matching-tag.
>>> EOF
>>> (
>>> @@ -1253,6 +1310,20 @@ test_expect_success
>>> '__git_complete_fetch_refspecs - simple' '
>>> test_cmp expected out
>>> '
>>> +test_expect_success '__git_complete_fetch_refspecs - with slash' '
>>> + sed -e "s/Z$//" >expected <<-EOF &&
>>> + HEAD:HEAD Z
>>> + HEAD:HEAD Z
>>> + branch/with/slash:branch/with/slash Z
>>> + EOF
>>> + (
>>> + cur= &&
>>> + __git_complete_fetch_refspecs remote/with/slash &&
>>> + print_comp
>>> + ) &&
>>> + test_cmp expected out
>>> +'
>>> +
>>> test_expect_success '__git_complete_fetch_refspecs - matching' '
>>> sed -e "s/Z$//" >expected <<-EOF &&
>>> branch-in-other:branch-in-other Z
>>> @@ -1333,8 +1404,8 @@ test_expect_success
>>> '__git_complete_worktree_paths with -C' '
>>> test_expect_success 'git switch - with no options, complete local
>>> branches and unique remote branch names for DWIM logic' '
>>> test_completion "git switch " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1480,8 +1551,8 @@ test_expect_success 'git-bisect - existing view
>>> subcommand is recognized and ena
>>> test_expect_success 'git checkout - completes refs and unique
>>> remote branches for DWIM' '
>>> test_completion "git checkout " <<-\EOF
>>> HEAD Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1489,6 +1560,8 @@ test_expect_success 'git checkout - completes
>>> refs and unique remote branches fo
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1508,8 +1581,8 @@ test_expect_success 'git switch - with
>>> GIT_COMPLETION_CHECKOUT_NO_GUESS=1, compl
>>> test_expect_success 'git switch - --guess overrides
>>> GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete local branches and
>>> unique remote names for DWIM logic' '
>>> GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch
>>> --guess " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1518,8 +1591,8 @@ test_expect_success 'git switch - --guess
>>> overrides GIT_COMPLETION_CHECKOUT_NO_G
>>> test_expect_success 'git switch - a later --guess overrides
>>> previous --no-guess, complete local and remote unique branches for
>>> DWIM' '
>>> test_completion "git switch --no-guess --guess " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1542,14 +1615,16 @@ test_expect_success 'git checkout - with
>>> GIT_COMPLETION_NO_GUESS=1 only complete
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> test_expect_success 'git checkout - --guess overrides
>>> GIT_COMPLETION_NO_GUESS=1, complete refs and unique remote branches
>>> for DWIM' '
>>> GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git
>>> checkout --guess " <<-\EOF
>>> HEAD Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1557,6 +1632,8 @@ test_expect_success 'git checkout - --guess
>>> overrides GIT_COMPLETION_NO_GUESS=1,
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1569,14 +1646,16 @@ test_expect_success 'git checkout - with --
>>> no-guess, only completes refs' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> test_expect_success 'git checkout - a later --guess overrides
>>> previous --no-guess, complete refs and unique remote branches for
>>> DWIM' '
>>> test_completion "git checkout --no-guess --guess " <<-\EOF
>>> HEAD Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1584,6 +1663,8 @@ test_expect_success 'git checkout - a later --
>>> guess overrides previous --no-gues
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1596,6 +1677,8 @@ test_expect_success 'git checkout - a later --
>>> no-guess overrides previous --gues
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1609,6 +1692,8 @@ test_expect_success 'git checkout - with
>>> checkout.guess = false, only completes
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1616,8 +1701,8 @@ test_expect_success 'git checkout - with
>>> checkout.guess = true, completes refs a
>>> test_config checkout.guess true &&
>>> test_completion "git checkout " <<-\EOF
>>> HEAD Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1625,6 +1710,8 @@ test_expect_success 'git checkout - with
>>> checkout.guess = true, completes refs a
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1632,8 +1719,8 @@ test_expect_success 'git checkout - a later --
>>> guess overrides previous checkout.
>>> test_config checkout.guess false &&
>>> test_completion "git checkout --guess " <<-\EOF
>>> HEAD Z
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -1641,6 +1728,8 @@ test_expect_success 'git checkout - a later --
>>> guess overrides previous checkout.
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1654,6 +1743,8 @@ test_expect_success 'git checkout - a later --
>>> no-guess overrides previous checko
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1666,6 +1757,8 @@ test_expect_success 'git switch - with --
>>> detach, complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1678,6 +1771,8 @@ test_expect_success 'git checkout - with --
>>> detach, complete only references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1850,6 +1945,8 @@ test_expect_success 'git switch - with -d,
>>> complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1862,6 +1959,8 @@ test_expect_success 'git checkout - with -d,
>>> complete only references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1870,11 +1969,15 @@ test_expect_success 'git switch - with --
>>> track, complete only remote branches' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> test_completion "git switch -t " <<-\EOF
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1883,11 +1986,15 @@ test_expect_success 'git checkout - with --
>>> track, complete only remote branches'
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> test_completion "git checkout -t " <<-\EOF
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1907,6 +2014,8 @@ test_expect_success 'git checkout - with --no-
>>> track, complete only local referen
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1919,6 +2028,8 @@ test_expect_success 'git switch - with -c,
>>> complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1931,6 +2042,8 @@ test_expect_success 'git switch - with -C,
>>> complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1943,6 +2056,8 @@ test_expect_success 'git switch - with -c and
>>> --track, complete all references'
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1955,6 +2070,8 @@ test_expect_success 'git switch - with -C and
>>> --track, complete all references'
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1967,6 +2084,8 @@ test_expect_success 'git switch - with -c and
>>> --no-track, complete all reference
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1979,6 +2098,8 @@ test_expect_success 'git switch - with -C and
>>> --no-track, complete all reference
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -1991,6 +2112,8 @@ test_expect_success 'git checkout - with -b,
>>> complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2003,6 +2126,8 @@ test_expect_success 'git checkout - with -B,
>>> complete all references' '
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2015,6 +2140,8 @@ test_expect_success 'git checkout - with -b and
>>> --track, complete all references
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2027,6 +2154,8 @@ test_expect_success 'git checkout - with -B and
>>> --track, complete all references
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2039,6 +2168,8 @@ test_expect_success 'git checkout - with -b and
>>> --no-track, complete all referen
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2051,13 +2182,15 @@ test_expect_success 'git checkout - with -B
>>> and --no-track, complete all referen
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> test_expect_success 'git switch - for -c, complete local branches
>>> and unique remote branches' '
>>> test_completion "git switch -c " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2066,8 +2199,8 @@ test_expect_success 'git switch - for -c,
>>> complete local branches and unique rem
>>> test_expect_success 'git switch - for -C, complete local branches
>>> and unique remote branches' '
>>> test_completion "git switch -C " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2104,8 +2237,8 @@ test_expect_success 'git switch - for -C with
>>> --no-track, complete local branche
>>> test_expect_success 'git checkout - for -b, complete local branches
>>> and unique remote branches' '
>>> test_completion "git checkout -b " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2114,8 +2247,8 @@ test_expect_success 'git checkout - for -b,
>>> complete local branches and unique r
>>> test_expect_success 'git checkout - for -B, complete local branches
>>> and unique remote branches' '
>>> test_completion "git checkout -B " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2152,8 +2285,8 @@ test_expect_success 'git checkout - for -B with
>>> --no-track, complete local branc
>>> test_expect_success 'git switch - with --orphan completes local
>>> branch names and unique remote branch names' '
>>> test_completion "git switch --orphan " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2168,8 +2301,8 @@ test_expect_success 'git switch - --orphan with
>>> branch already provided complete
>>> test_expect_success 'git checkout - with --orphan completes local
>>> branch names and unique remote branch names' '
>>> test_completion "git checkout --orphan " <<-\EOF
>>> - HEAD Z
>>> branch-in-other Z
>>> + branch/with/slash Z
>>> main Z
>>> main-in-other Z
>>> matching-branch Z
>>> @@ -2185,6 +2318,8 @@ test_expect_success 'git checkout - --orphan
>>> with branch already provided comple
>>> other/HEAD Z
>>> other/branch-in-other Z
>>> other/main-in-other Z
>>> + remote/with/slash/HEAD Z
>>> + remote/with/slash/branch/with/slash Z
>>> EOF
>>> '
>>> @@ -2199,7 +2334,8 @@ test_expect_success 'git restore completes
>>> modified files' '
>>> test_expect_success 'teardown after ref completion' '
>>> git branch -d matching-branch &&
>>> git tag -d matching-tag &&
>>> - git remote remove other
>>> + git remote remove other &&
>>> + git remote remove remote/with/slash
>>> '
>>
>