Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] Re: git completion is really slow for some git commands.



Hello Brice,

Brice Figureau <brice+zsh@xxxxxxxxxxxxxxxx> wrote:
> Unfortunately git completion, although working fine, is extremely slow
> as soon as you have a moderately sized git repository. In my case, my
> checkout have 13000 files and about 6000 commits.
>
> git log <TAB> takes about 15s using 100% CPU to complete on my 2.4GHZ P4
> computer. OK, that's now an old computer, but I find that a little bit
> slow to just sort/split 13000 strings.
>
> It all boils down to the following chain of events:
>  * git log completion uses __git_files
>
>  * _git_files uses "git ls-files". In itself ls-files on this repository
> on cold cache takes about 70ms (which is short, compared to the 15s of
> the whole thing).
>
>  * the result of git ls-files is splitted by \0 and stored in a shell
> array. This operation takes about 350ms. That's still fast compared to
> the 15s of the whole execution time. Note: that's not as fast we would
> think it could be.
>
>  * this shell array is then passed to _multi_parts for path splitting of
> each element. This is this operation that takes age. As soon as I change
> the _multi_parts code to just call a naive compadd and return, the
> completion is (almost) immediate, and seems to work fine.

Can you try this patch? It doesn't change anything if you didn't specify
anything, i.e. git log -- <TAB> takes still very long. But it optimizes
the case when you specify anything. Try git log -- some/thing<TAB>.

commit e985683fe8d805228ad88903261f20181de23f1e
Author: Jörg Sommer <joerg@xxxxxxxxxxxx>
Date:   Mon Oct 13 01:58:03 2008 +0200

    Prefilter the completion for _multi_parts
    
    The _multi_parts function consumes very much time, if the array with the
    possible completions is large. This happens often in large git
    repositories like the kernel git repository. To reduce the workload of
    _multi_parts filter out does entries from the array, they aren't possible
    completions. When the user specifies the path foo/bar only consider paths
    matching the pattern foo*/bar*.

diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index c617613..5fd637a 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -2761,6 +2761,7 @@ __git_files () {
   files=(${(ps:\0:)"$(_call_program files git ls-files -z $ls_opts $opts 2>/dev/null)"})
   __git_command_successful || return
 
+  [[ -n $PREFIX ]] && files=${(M)files:#${~PREFIX//\//*/}*}
   _wanted files expl 'index file' _multi_parts $@ - / files
 }
 
@@ -2859,6 +2860,7 @@ __git_tree_files () {
   fi
 
   local expl
+  [[ -n $PREFIX ]] && tree_files=${(M)tree_files:#${~PREFIX//\//*/}*}
   _wanted files expl 'tree file' _multi_parts -f $@ -- / tree_files
 }
 

Question to everybody else: Should such a filter go to _multi_parts
itself?

Bye, Jörg.
-- 
Alles, wovor wir Angst haben müssen, ist die Angst selbst.
       	     	       	     	     	 (Franklin D. Roosevelt)



Messages sorted by: Reverse Date, Date, Thread, Author