From f674bb80784683f65c20264ce20afdd0a7669ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:35 +0200 Subject: completion: document __gitcomp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I always forget which argument is which, and got tired of figuring it out over and over again. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 888e8e10cc..45cbd2b940 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -485,8 +485,13 @@ _get_comp_words_by_ref () fi fi -# __gitcomp accepts 1, 2, 3, or 4 arguments -# generates completion reply with compgen +# Generates completion reply with compgen, appending a space to possible +# completion words, if necessary. +# It accepts 1 to 4 arguments: +# 1: List of possible completion words. +# 2: A prefix to be added to each possible completion word (optional). +# 3: Generate possible completion matches for this word (optional). +# 4: A suffix to be appended to each possible completion word (optional). __gitcomp () { local cur_="$cur" -- cgit v1.2.3 From a31e62629a1408bca540f505f2dc4ab8a9999f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 15 Oct 2011 14:57:23 +0200 Subject: completion: optimize refs completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a unique command or option is completed, in most cases it is a good thing to add a trailing a space, but sometimes it doesn't make sense, e.g. when the completed word is an option taking an argument ('--option=') or a configuration section ('core.'). Therefore the completion script uses the '-o nospace' option to prevent bash from automatically appending a space to unique completions, and it has the __gitcomp() function to add that trailing space only when necessary. See 72e5e989 (bash: Add space after unique command name is completed., 2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config., 2007-02-04), and b3391775 (bash: Support unique completion when possible., 2007-02-04). __gitcomp() therefore iterates over all possible completion words it got as argument, and checks each word whether a trailing space is necessary or not. This is ok for commands, options, etc., i.e. when the number of words is relatively small, but can be noticeably slow for large number of refs. However, while options might or might not need that trailing space, refs are always handled uniformly and always get that trailing space (or a trailing '.' for 'git config branch..'). Since refs listed by __git_refs() & co. are separated by newline, this allows us some optimizations with 'compgen'. So, add a specialized variant of __gitcomp() that only deals with possible completion words separated by a newline and uniformly appends the trailing space to all words using 'compgen -S " "' (or any other suffix, if specified), so no iteration over all words is needed. But we need to fiddle with IFS, because the default IFS containing a space would cause the added space suffix to be stripped off when compgen's output is stored in the COMPREPLY array. Therefore we use only newline as IFS, hence the requirement for the newline-separated possible completion words. Convert all callsites of __gitcomp() where it's called with refs, i.e. when it gets the output of either __git_refs(), __git_heads(), __git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git for-each-ref' somewhere in _git_config(). Also convert callsites where it gets other uniformly handled newline separated word lists, i.e. either remotes from __git_remotes(), names of set configuration variables from __git_config_get_set_variables(), stashes, or commands. Here are some timing results for dealing with 10000 refs. Before: $ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)" $ time __gitcomp "$refs" real 0m1.134s user 0m1.060s sys 0m0.130s After: $ time __gitcomp_nl "$refs" real 0m0.373s user 0m0.360s sys 0m0.020s Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 115 ++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 45cbd2b940..703135655f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -512,6 +512,31 @@ __gitcomp () esac } +# Generates completion reply with compgen from newline-separated possible +# completion words by appending a space to all of them. +# It accepts 1 to 4 arguments: +# 1: List of possible completion words, separated by a single newline. +# 2: A prefix to be added to each possible completion word (optional). +# 3: Generate possible completion matches for this word (optional). +# 4: A suffix to be appended to each possible completion word instead of +# the default space (optional). If specified but empty, nothing is +# appended. +__gitcomp_nl () +{ + local s=$'\n' IFS=' '$'\t'$'\n' + local cur_="$cur" suffix=" " + + if [ $# -gt 2 ]; then + cur_="$3" + if [ $# -gt 3 ]; then + suffix="$4" + fi + fi + + IFS=$s + COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_")) +} + # __git_heads accepts 0 or 1 arguments (to pass to __gitdir) __git_heads () { @@ -716,15 +741,15 @@ __git_complete_revlist_file () *...*) pfx="${cur_%...*}..." cur_="${cur_#*...}" - __gitcomp "$(__git_refs)" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" ;; *..*) pfx="${cur_%..*}.." cur_="${cur_#*..}" - __gitcomp "$(__git_refs)" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" ;; *) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; esac } @@ -764,7 +789,7 @@ __git_complete_remote_or_refspec () c=$((++c)) done if [ -z "$remote" ]; then - __gitcomp "$(__git_remotes)" + __gitcomp_nl "$(__git_remotes)" return fi if [ $no_complete_refspec = 1 ]; then @@ -789,23 +814,23 @@ __git_complete_remote_or_refspec () case "$cmd" in fetch) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_" else - __gitcomp "$(__git_refs)" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" fi ;; pull) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" else - __gitcomp "$(__git_refs)" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" fi ;; push) if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs)" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" else - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_" + __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" fi ;; esac @@ -1084,7 +1109,7 @@ _git_archive () return ;; --remote=*) - __gitcomp "$(__git_remotes)" "" "${cur##--remote=}" + __gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}" return ;; --*) @@ -1115,7 +1140,7 @@ _git_bisect () case "$subcommand" in bad|good|reset|skip|start) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; *) COMPREPLY=() @@ -1146,9 +1171,9 @@ _git_branch () ;; *) if [ $only_local_ref = "y" -a $has_r = "n" ]; then - __gitcomp "$(__git_heads)" + __gitcomp_nl "$(__git_heads)" else - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" fi ;; esac @@ -1195,7 +1220,7 @@ _git_checkout () if [ -n "$(__git_find_on_cmdline "$flags")" ]; then track='' fi - __gitcomp "$(__git_refs '' $track)" + __gitcomp_nl "$(__git_refs '' $track)" ;; esac } @@ -1212,7 +1237,7 @@ _git_cherry_pick () __gitcomp "--edit --no-commit" ;; *) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; esac } @@ -1266,7 +1291,7 @@ _git_commit () ;; --reuse-message=*|--reedit-message=*|\ --fixup=*|--squash=*) - __gitcomp "$(__git_refs)" "" "${cur#*=}" + __gitcomp_nl "$(__git_refs)" "" "${cur#*=}" return ;; --untracked-files=*) @@ -1297,7 +1322,7 @@ _git_describe () " return esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } __git_diff_common_options="--stat --numstat --shortstat --summary @@ -1456,7 +1481,7 @@ _git_grep () ;; esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_help () @@ -1514,7 +1539,7 @@ _git_ls_files () _git_ls_remote () { - __gitcomp "$(__git_remotes)" + __gitcomp_nl "$(__git_remotes)" } _git_ls_tree () @@ -1610,7 +1635,7 @@ _git_merge () __gitcomp "$__git_merge_options" return esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_mergetool () @@ -1630,7 +1655,7 @@ _git_mergetool () _git_merge_base () { - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_mv () @@ -1661,7 +1686,7 @@ _git_notes () ,*) case "${words[cword-1]}" in --ref) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; *) __gitcomp "$subcommands --ref" @@ -1670,7 +1695,7 @@ _git_notes () ;; add,--reuse-message=*|append,--reuse-message=*|\ add,--reedit-message=*|append,--reedit-message=*) - __gitcomp "$(__git_refs)" "" "${cur#*=}" + __gitcomp_nl "$(__git_refs)" "" "${cur#*=}" ;; add,--*|append,--*) __gitcomp '--file= --message= --reedit-message= @@ -1689,7 +1714,7 @@ _git_notes () -m|-F) ;; *) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; esac ;; @@ -1717,12 +1742,12 @@ _git_push () { case "$prev" in --repo) - __gitcomp "$(__git_remotes)" + __gitcomp_nl "$(__git_remotes)" return esac case "$cur" in --repo=*) - __gitcomp "$(__git_remotes)" "" "${cur##--repo=}" + __gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}" return ;; --*) @@ -1760,7 +1785,7 @@ _git_rebase () return esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_reflog () @@ -1771,7 +1796,7 @@ _git_reflog () if [ -z "$subcommand" ]; then __gitcomp "$subcommands" else - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" fi } @@ -1853,23 +1878,23 @@ _git_config () { case "$prev" in branch.*.remote) - __gitcomp "$(__git_remotes)" + __gitcomp_nl "$(__git_remotes)" return ;; branch.*.merge) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" return ;; remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" - __gitcomp "$(__git_refs_remotes "$remote")" + __gitcomp_nl "$(__git_refs_remotes "$remote")" return ;; remote.*.push) local remote="${prev#remote.}" remote="${remote%.push}" - __gitcomp "$(git --git-dir="$(__gitdir)" \ + __gitcomp_nl "$(git --git-dir="$(__gitdir)" \ for-each-ref --format='%(refname):%(refname)' \ refs/heads)" return @@ -1916,7 +1941,7 @@ _git_config () return ;; --get|--get-all|--unset|--unset-all) - __gitcomp "$(__git_config_get_set_variables)" + __gitcomp_nl "$(__git_config_get_set_variables)" return ;; *.*) @@ -1942,7 +1967,7 @@ _git_config () ;; branch.*) local pfx="${cur%.*}." cur_="${cur#*.}" - __gitcomp "$(__git_heads)" "$pfx" "$cur_" "." + __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "." return ;; guitool.*.*) @@ -1971,7 +1996,7 @@ _git_config () pager.*) local pfx="${cur%.*}." cur_="${cur#*.}" __git_compute_all_commands - __gitcomp "$__git_all_commands" "$pfx" "$cur_" + __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" return ;; remote.*.*) @@ -1984,7 +2009,7 @@ _git_config () ;; remote.*) local pfx="${cur%.*}." cur_="${cur#*.}" - __gitcomp "$(__git_remotes)" "$pfx" "$cur_" "." + __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." return ;; url.*.*) @@ -2285,7 +2310,7 @@ _git_remote () case "$subcommand" in rename|rm|show|prune) - __gitcomp "$(__git_remotes)" + __gitcomp_nl "$(__git_remotes)" ;; update) local i c='' IFS=$'\n' @@ -2303,7 +2328,7 @@ _git_remote () _git_replace () { - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_reset () @@ -2316,7 +2341,7 @@ _git_reset () return ;; esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_revert () @@ -2327,7 +2352,7 @@ _git_revert () return ;; esac - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" } _git_rm () @@ -2426,7 +2451,7 @@ _git_stash () COMPREPLY=() ;; show,*|apply,*|drop,*|pop,*|branch,*) - __gitcomp "$(git --git-dir="$(__gitdir)" stash list \ + __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; *) @@ -2560,7 +2585,7 @@ _git_tag () i="${words[c]}" case "$i" in -d|-v) - __gitcomp "$(__git_tags)" + __gitcomp_nl "$(__git_tags)" return ;; -f) @@ -2576,13 +2601,13 @@ _git_tag () ;; -*|tag) if [ $f = 1 ]; then - __gitcomp "$(__git_tags)" + __gitcomp_nl "$(__git_tags)" else COMPREPLY=() fi ;; *) - __gitcomp "$(__git_refs)" + __gitcomp_nl "$(__git_refs)" ;; esac } -- cgit v1.2.3 From abf05987de7b61972e85392ca2f1a4fc25046e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:37 +0200 Subject: completion: make refs completion consistent for local and remote repos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a local repository the __git_refs() completion helper function lists refs under 'refs/(tags|heads|remotes)/', plus some special refs like HEAD and ORIG_HEAD. For a remote repository, however, it lists all refs. Fix this inconsistency by specifying refs filter patterns for 'git ls-remote' to only list refs under 'refs/(tags|heads|remotes)/'. For now this makes it impossible to complete refs outside of 'refs/(tags|heads|remotes)/' in a remote repository, but a followup patch will resurrect that. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 703135655f..3f7a776a9d 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -616,13 +616,11 @@ __git_refs () fi return fi - for i in $(git ls-remote "$dir" 2>/dev/null); do + for i in $(git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null); do case "$is_hash,$i" in y,*) is_hash=n ;; n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; - n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;; + n,refs/*) is_hash=y; echo "${i#refs/*/}" ;; n,*) is_hash=y; echo "$i" ;; esac done -- cgit v1.2.3 From d8c0453e1a81db03880a9f237675d82cdc290d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:38 +0200 Subject: completion: improve ls-remote output filtering in __git_refs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remote-handling part of __git_refs() has a nice for loop and state machine case statement to iterate over all words from the output of 'git ls-remote' to identify object names and ref names. Since each line in the output of 'git ls-remote' consists of an object name and a ref name, we can do more effective filtering by using a while-read loop and letting bash's word splitting take care of object names. This way the code is easier to understand and the loop will need only half the number of iterations than before. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 3f7a776a9d..5632c88627 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -580,7 +580,7 @@ __git_tags () # by checkout for tracking branches __git_refs () { - local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}" + local i hash dir="$(__gitdir "${1-}")" track="${2-}" local format refs if [ -d "$dir" ]; then case "$cur" in @@ -616,12 +616,12 @@ __git_refs () fi return fi - for i in $(git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/*) is_hash=y; echo "${i#refs/*/}" ;; - n,*) is_hash=y; echo "$i" ;; + git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \ + while read hash i; do + case "$i" in + *^{}) ;; + refs/*) echo "${i#refs/*/}" ;; + *) echo "$i" ;; esac done } -- cgit v1.2.3 From fb772cca2bd38e97a3b23d5b241a8961156b681b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:39 +0200 Subject: completion: support full refs from remote repositories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the __git_refs() completion helper function lists refs from a local repository, it usually lists the refs' short name, except when it needs to provide completion for words starting with refs, because in that case it lists full ref names, see 608efb87 (bash: complete full refs, 2008-11-28). Add the same functionality to the code path dealing with remote repositories, too. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 5632c88627..8867e092b6 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -616,14 +616,27 @@ __git_refs () fi return fi - git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \ - while read hash i; do - case "$i" in - *^{}) ;; - refs/*) echo "${i#refs/*/}" ;; - *) echo "$i" ;; - esac - done + case "$cur" in + refs|refs/*) + git ls-remote "$dir" "$cur*" 2>/dev/null | \ + while read hash i; do + case "$i" in + *^{}) ;; + *) echo "$i" ;; + esac + done + ;; + *) + git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \ + while read hash i; do + case "$i" in + *^{}) ;; + refs/*) echo "${i#refs/*/}" ;; + *) echo "$i" ;; + esac + done + ;; + esac } # __git_refs2 requires 1 argument (to pass to __git_refs) -- cgit v1.2.3 From d79bcf2cf21ddb8c3fcbd95bafa431f872d47a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:40 +0200 Subject: completion: query only refs/heads/ in __git_refs_remotes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __git_refs_remotes() is used to provide completion for refspecs to set 'remote.*.fetch' config variables for branches on the given remote. So it's really only interested in refs under 'refs/heads/', but it queries the remote for all its refs and then filters out all refs outside of 'refs/heads/'. Let 'git ls-remote' do the filtering. Also remove the unused $cmd variable from __git_refs_remotes(). Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8867e092b6..396c8e98f7 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -651,17 +651,14 @@ __git_refs2 () # __git_refs_remotes requires 1 argument (to pass to ls-remote) __git_refs_remotes () { - local cmd i is_hash=y - for i in $(git ls-remote "$1" 2>/dev/null); do - case "$is_hash,$i" in - n,refs/heads/*) + local i is_hash=y + for i in $(git ls-remote "$1" 'refs/heads/*' 2>/dev/null); do + case "$is_hash" in + n) is_hash=y echo "$i:refs/remotes/$1/${i#refs/heads/}" ;; - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y;; - n,*) is_hash=y; ;; + y) is_hash=n ;; esac done } -- cgit v1.2.3 From 48058f5df49fb9005418a7d025b374988908c0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:41 +0200 Subject: completion: improve ls-remote output filtering in __git_refs_remotes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This follows suit of a previous patch for __git_refs(): use a while-read loop and let bash's word splitting get rid of object names from 'git ls-remote's output. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 396c8e98f7..f992b1399d 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -651,15 +651,10 @@ __git_refs2 () # __git_refs_remotes requires 1 argument (to pass to ls-remote) __git_refs_remotes () { - local i is_hash=y - for i in $(git ls-remote "$1" 'refs/heads/*' 2>/dev/null); do - case "$is_hash" in - n) - is_hash=y - echo "$i:refs/remotes/$1/${i#refs/heads/}" - ;; - y) is_hash=n ;; - esac + local i hash + git ls-remote "$1" 'refs/heads/*' 2>/dev/null | \ + while read hash i; do + echo "$i:refs/remotes/$1/${i#refs/heads/}" done } -- cgit v1.2.3 From d51a8ecd5fedb6fd09a14fc1b07f8922d6963743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:42 +0200 Subject: completion: fast initial completion for config 'remote.*.fetch' value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refspecs for branches in a remote repository start with 'refs/heads/', so completing those refspecs with 'git config remote.origin.fetch ' always offers 'refs/heads/' first, because that's the unique part of the possible refspecs. But it does so only after querying the remote with 'git ls-remote', which can take a while when the request goes through some slower network to a remote server. Don't waste the user's time and offer 'refs/heads/' right away for 'git config remote.origin.fetch '. The reason for putting 'refs/heads/' directly into COMPREPLY instead of using __gitcomp() is to avoid __gitcomp() adding a trailing space. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f992b1399d..c76b645bed 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1891,6 +1891,10 @@ _git_config () remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" + if [ -z "$cur" ]; then + COMPREPLY=("refs/heads/") + return + fi __gitcomp_nl "$(__git_refs_remotes "$remote")" return ;; -- cgit v1.2.3 From 6486ca6d77eaf4109b26b70da0b3a0158868e22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Sat, 8 Oct 2011 16:54:43 +0200 Subject: completion: remove broken dead code from __git_heads() and __git_tags() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __git_heads() was introduced in 5de40f5 (Teach bash about git-repo-config., 2006-11-27), and __git_tags() in 88e21dc (Teach bash about completing arguments for git-tag, 2007-08-31). As their name suggests, __git_heads() is supposed to list only branches, and __git_tags() only tags. Since their introduction both of these functions consist of two distinct parts. The first part gets branches or tags, respectively, from a local repositoty using 'git for-each-ref'. The second part queries a remote repository given as argument using 'git ls-remote'. These remote-querying parts are broken in both functions since their introduction, because they list both branches and tags from the remote repository. (The 'git ls-remote' query is not limited to list only heads or tags, respectively, and the for loop filtering the query results prints everything except dereferenced tags.) This breakage could be easily fixed by passing the '--heads' or '--tags' options or appropriate refs patterns to the 'git ls-remote' invocations. However, that no one noticed this breakage yet is probably not a coincidence: neither of these two functions were used to query a remote repository, the remote-querying parts were dead code already upon thier introduction and remained dead ever since. Since those parts of code are broken, are and were never used, stop the bit-rotting and remove them. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c76b645bed..16623d7c3f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -537,42 +537,24 @@ __gitcomp_nl () COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_")) } -# __git_heads accepts 0 or 1 arguments (to pass to __gitdir) __git_heads () { - local cmd i is_hash=y dir="$(__gitdir "${1-}")" + local dir="$(__gitdir)" if [ -d "$dir" ]; then git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ refs/heads return fi - for i in $(git ls-remote "${1-}" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; - n,*) is_hash=y; echo "$i" ;; - esac - done } -# __git_tags accepts 0 or 1 arguments (to pass to __gitdir) __git_tags () { - local cmd i is_hash=y dir="$(__gitdir "${1-}")" + local dir="$(__gitdir)" if [ -d "$dir" ]; then git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ refs/tags return fi - for i in $(git ls-remote "${1-}" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; - n,*) is_hash=y; echo "$i" ;; - esac - done } # __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments -- cgit v1.2.3