Skip to content

Commit a364e98

Browse files
szedergitster
authored andcommitted
completion: let 'ls-files' and 'diff-index' filter matching paths
During git-aware path completion, e.g. 'git rm dir/fil<TAB>', both 'git ls-files' and 'git diff-index' list all paths in the given 'dir/' matching certain criteria (cached, modified, untracked, etc.) appropriate for the given git command, even paths whose names don't begin with 'fil'. This comes with a considerable performance penalty when the directory in question contains a lot of paths, but the current word can be uniquely completed or when only a handful of those paths match the current word. Reduce the number of iterations in this codepath from the number of paths to the number of matching paths by specifying an appropriate globbing pattern to 'git ls-files' and 'git diff-index' to list only paths that match the current word to be completed. Note that both commands treat backslashes as escape characters in their file arguments, e.g. to preserve the literal meaning of globbing characters, so we have to double every backslash in the globbing pattern. This is why one of the path completion tests specifically checks the completion of a path containing a literal backslash character (that test still fails, though, because both commands output such paths enclosed in double quotes and the special characters escaped; a later patch in this series will deal with those). This speeds up path completion considerably when there are a lot of non-matching paths to be filtered out. Uniquely completing a tracked filename at the top of the worktree in linux.git (over 62k files), i.e. what's doing all the hard work behind 'git rm Mak<TAB>' to complete 'Makefile': Before this patch, best of five, on Linux: $ time cur=Mak __git_complete_index_file real 0m2.159s user 0m1.299s sys 0m1.089s After: real 0m0.033s user 0m0.023s sys 0m0.015s Difference: -98.5% Speedup: 65.4x Signed-off-by: SZEDER Gábor <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f12785a commit a364e98

File tree

2 files changed

+7
-5
lines changed

2 files changed

+7
-5
lines changed

contrib/completion/git-completion.bash

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,11 @@ __git_ls_files_helper ()
436436
{
437437
if [ "$2" == "--committable" ]; then
438438
__git -C "$1" -c core.quotePath=false diff-index \
439-
--name-only --relative HEAD
439+
--name-only --relative HEAD -- "${3//\\/\\\\}*"
440440
else
441441
# NOTE: $2 is not quoted in order to support multiple options
442442
__git -C "$1" -c core.quotePath=false ls-files \
443-
--exclude-standard $2
443+
--exclude-standard $2 -- "${3//\\/\\\\}*"
444444
fi
445445
}
446446

@@ -451,11 +451,12 @@ __git_ls_files_helper ()
451451
# If provided, only files within the specified directory are listed.
452452
# Sub directories are never recursed. Path must have a trailing
453453
# slash.
454+
# 3: List only paths matching this path component (optional).
454455
__git_index_files ()
455456
{
456-
local root="$2" file
457+
local root="$2" match="$3" file
457458

458-
__git_ls_files_helper "$root" "$1" |
459+
__git_ls_files_helper "$root" "$1" "$match" |
459460
while read -r file; do
460461
case "$file" in
461462
?*/*) echo "${file%%/*}" ;;
@@ -483,7 +484,7 @@ __git_complete_index_file ()
483484
cur_="$dequoted_word"
484485
esac
485486

486-
__gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_"
487+
__gitcomp_file "$(__git_index_files "$1" "$pfx" "$cur_")" "$pfx" "$cur_"
487488
}
488489

489490
# Lists branches from the local repository.

t/t9902-completion.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ test_expect_success 'complete files - UTF-8 in ls-files output' '
15151515
"árvíztűrő/Сайн яваарай"
15161516
'
15171517

1518+
# Testing with a path containing a backslash is important.
15181519
if test_have_prereq !MINGW &&
15191520
mkdir 'New\Dir' 2>/dev/null &&
15201521
touch 'New\Dir/New"File.c' 2>/dev/null

0 commit comments

Comments
 (0)