threads / discuss / 34878

Bash completion doing full tree traversal?

Subject: Bash completion doing full tree traversal?

## tl;dr

4 messages between Sep 8, 2013 and Sep 19, 2013.

replies: 3people: 3as markdown or json

Isaac Levy· Sep 8, 2013, 12:12 UTC · lore

I experienced a weird stall from git bash completion: $ git add p<TAB>

I did some investigation and found this call trace:
+ __git_index_files '--others --modified' ''
   ---> git ls-files --exclude-standard --others --modified

This bash function captures output of the git call and strips all but the base directory or base filename. The results are limited to entries in the current directory.

Appears to be from fea16b47b603e and first released in v1.8.2 (I have 1.8.4).
Isaac
Isaac Levy· Sep 16, 2013, 15:54 UTC · re: Isaac Levy · lore

Re: Bash completion doing full tree traversal?

I should clarify that I had an untracked directory which contained a significant number of files; I can fix by adding it to gitignore. Still, the long delay & tree traversal were unexpected.

Isaac
On Sun, Sep 8, 2013 at 2:12 PM, Isaac Levy <ilevy@google.com> wrote:
Show 15 quoted lines
> I experienced a weird stall from git bash completion:
> $ git add p<TAB>
>
> I did some investigation and found this call trace:
>
> + __git_index_files '--others --modified' ''
>    ---> git ls-files --exclude-standard --others --modified
>
> This bash function captures output of the git call and strips all but
> the base directory or base filename.  The results are limited to
> entries in the current directory.
>
> Appears to be from fea16b47b603e and first released in v1.8.2 (I have 1.8.4).
>
> Isaac
SZEDER Gábor· Sep 18, 2013, 17:06 UTC · re: Isaac Levy · lore

[PATCH] completion: improve untracked directory filtering for filename completion

Similar to Bash's default filename completion, our git-aware filename completion stops at directory boundaries, i.e. it doesn't offer the full 'path/to/file' at first, but only 'path/'. To achieve that the completion script runs 'git ls-files' with specific command line options to get the list of relevant paths under the current directory, and then processes each path to strip all but the base directory or filename (see __git_index_files()).

To offer only modified and untracked files for 'git add' the completion script runs 'git ls-files --exclude-standard --others --modified'. This command lists all non-ignored files in untracked directories, which leads to a noticeable delay caused by the processing mentioned above if there are a lot of such files (__git_index_files() specifies '--exclude-standard' internally):

  $ mkdir untracked-dir
  $ for i in {1..10000} ; do >untracked-dir/$i ; done
  $ time __git_index_files "--others --modified"
  untracked-dir
  real	0m0.537s
  user	0m0.452s
  sys	0m0.160s

Eliminate this delay by additionally passing the '--directory --no-empty-directory' options to 'git ls-files' to show only the directory name of non-empty untracked directories instead their whole content:

  $ time __git_index_files "--others --modified --directory --no-empty-directory"
  untracked-dir
  real	0m0.029s
  user	0m0.020s
  sys	0m0.004s

Filename completion for 'git clean' suffers from the same delay, as it offers untracked files, too. The fix could be the same, but since it actually makes sense to 'git clean' empty directories, in this case we only pass the '--directory' option to 'git ls-files'.

Reported-by: Isaac Levy <ilevy@google.com>
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
---
 contrib/completion/git-completion.bash | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index e1b7313072..86f77345fd 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -901,7 +901,7 @@ _git_add ()
 	esac
 
 	# XXX should we check for --update and --all options ?
-	__git_complete_index_file "--others --modified"
+	__git_complete_index_file "--others --modified --directory --no-empty-directory"
 }
 
 _git_archive ()
@@ -1063,7 +1063,7 @@ _git_clean ()
 	esac
 
 	# XXX should we check for -x option ?
-	__git_complete_index_file "--others"
+	__git_complete_index_file "--others --directory"
 }
 
 _git_clone ()
-- 
1.8.4.366.g16e4e67
Jonathan Nieder· Sep 19, 2013, 19:31 UTC · re: SZEDER Gábor · lore

Re: [PATCH] completion: improve untracked directory filtering for filename completion

SZEDER Gábor wrote:
Show 18 quoted lines
>   $ time __git_index_files "--others --modified"
>   untracked-dir
>
>   real	0m0.537s
>   user	0m0.452s
>   sys	0m0.160s
>
> Eliminate this delay by additionally passing the '--directory
> --no-empty-directory' options to 'git ls-files' to show only the
> directory name of non-empty untracked directories instead their whole
> content:
>
>   $ time __git_index_files "--others --modified --directory --no-empty-directory"
>   untracked-dir
>
>   real	0m0.029s
>   user	0m0.020s
>   sys	0m0.004s
Nice.  This is what "git status" uses, too.
> Filename completion for 'git clean' suffers from the same delay, as it
> offers untracked files, too.  The fix could be the same, but since it
> actually makes sense to 'git clean' empty directories, in this case we
> only pass the '--directory' option to 'git ls-files'.
Also sensible.
For what it's worth,
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>

← back to recent threads