completion: let 'for-each-ref' filter remote branches for 'checkout' DWIMery
authorSZEDER Gábor <szeder.dev@gmail.com>
Thu, 23 Mar 2017 15:29:20 +0000 (16:29 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 23 Mar 2017 18:18:22 +0000 (11:18 -0700)
The code listing unique remote branches for 'git checkout's tracking
DWIMery outputs only remote branches that match the current word to be
completed, but the filtering is done in a shell loop iterating over
all remote refs.

Let 'git for-each-ref' do the filtering, as it can do so much more
efficiently and we can remove that shell loop entirely.

This speeds up refs completion for 'git checkout' considerably when
there are a lot of non-matching remote refs to be filtered out.
Uniquely completing a branch in a repository with 100k remote
branches, all packed, best of five:

On Linux, before:

$ time __git_complete_refs --cur=maste --track

real 0m1.993s
user 0m1.740s
sys 0m0.304s

After:

real 0m0.266s
user 0m0.248s
sys 0m0.012s

On Windows, before:

real 0m6.187s
user 0m3.358s
sys 0m2.121s

After:

real 0m0.750s
user 0m0.015s
sys 0m0.090s

Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
contrib/completion/git-completion.bash
index 206eaf0ca5457d48ad422e6a416a893cceca0e4e..394dcece6c324da6ca8bb15b7d85c831943e43ac 100644 (file)
@@ -422,15 +422,9 @@ __git_refs ()
                        # employ the heuristic used by git checkout
                        # Try to find a remote branch that matches the completion word
                        # but only output if the branch name is unique
-                       local ref entry
-                       __git for-each-ref --shell --format="ref=%(refname:strip=3)" \
-                               "refs/remotes/" | \
-                       while read -r entry; do
-                               eval "$entry"
-                               if [[ "$ref" == "$match"* ]]; then
-                                       echo "$ref"
-                               fi
-                       done | sort | uniq -u
+                       __git for-each-ref --format="%(refname:strip=3)" \
+                               "refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \
+                       sort | uniq -u
                fi
                return
        fi