Adobe
Adobe

Reputation: 13477

Why 'git ls-files' is not shown on tab completion?

Recently I found the command

git ls-files

and I find it very useful (see the it with -h option). Why doesn't it appear if i type git and then press Tab?

I mean - where is the list of "other" commands of git?

Upvotes: 13

Views: 1614

Answers (4)

VonC
VonC

Reputation: 1325155

With Git 2.18 (Q2 2018), the command line completion (in contrib/) learned to complete pathnames for various commands better.
And that includes git ls-files!

See commit 7d31407, commit 8b4c2e0 (18 May 2018), and commit 7b00342, commit 193757f, commit c1bc0a0, commit 9703797, commit 105c0ef, commit a364e98, commit f12785a, commit 3dfe23b, commit 6bf0ced, commit 722e31c, commit 5bb534a (16 Apr 2018) by SZEDER Gábor (szeder).
(Merged by Junio C Hamano -- gitster -- in commit 4ce7218, 30 May 2018)

completion: improve handling quoted paths in 'git ls-files's output

If any pathname contains backslash, double quote, tab, newline, or any control characters, 'git ls-files' and 'git diff-index' will enclose that pathname in double quotes and escape those special characters using C-style one-character escape sequences or \nnn octal values.

This prevents those files from being listed during git-aware path completion, because due to the quoting they will never match the current word to be completed.

That leads to various speed improvements:

completion: remove repeated dirnames with 'awk' during path completion

During git-aware path completion, after all the trailing path components have been removed from the output of 'git ls-files' and 'git diff-index', each directory name is repeated as many times as the number of listed paths it contains.
This can be a lot of repetitions, especially when invoking path completion close to the root of a big worktree.

Listing all tracked files (12) and directories (23) at the top of the worktree in linux.git (over 62k files), i.e. what's doing all the hard work behind 'git ls-files ':

Before this patch, best of five, using GNU awk on Linux:

real    0m0.069s
user    0m0.089s
sys     0m0.026s

After:

real    0m0.052s
user    0m0.072s
sys     0m0.014s

Difference: -24.6%

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.

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 ls-files Mak' 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

completion: fill COMPREPLY directly when completing paths

This speeds up path completion when there are a lot of paths matching the current word to be completed.
In a pathological repository with 100k files in a single directory, listing all those files:

Before this patch, best of five, using GNU awk on Linux:

$ time cur=dir/ __git_complete_index_file

real    0m0.983s
user    0m1.004s
sys     0m0.033s

After:

real    0m0.313s
user    0m0.341s
sys     0m0.029s

Difference: -68.2%
Speedup:      3.1x

Upvotes: 0

Penghe Geng
Penghe Geng

Reputation: 14621

Look at your ~/.git-completion.sh and the __git_list_porcelain_commands() function. The commands that git supports but won't tab-complete are listed there. Most of these commands are so-called "plumbing" commands, including ls-files. You can easily make them tab-completed by commenting the respective line. Like this:

#ls-files)         : plumbing;;
#ls-remote)        : plumbing;;
#ls-tree)          : plumbing;;

Upvotes: 6

Mikel
Mikel

Reputation: 25606

In a default install, Tab completion only lists names of commands as they appear in /bin, /usr/bin, etc. There is no file /usr/bin/git ls-files.

ls-files is a sub command that you will have to teach your shell about. Assuming you are using bash, you can run help complete to see what commands you can put in your .bashrc.

If your distribution supplies the bash-completion package, you can install it to save a lot of time:

apt-get install bash-completion  # on Debian/Ubuntu/etc.
yum install bash-completion      # on Fedora/Red Hat/etc.

But as manojlds points out, this won't work for the less commonly used git commands such as ls-files because bash-completion hides those from you. You would have to edit /etc/bash_completion.d/git to change that.

Upvotes: -2

manojlds
manojlds

Reputation: 301177

git ls-files is a plumbing command and many of these commands are "hidden" and rightfully so. Over time, many have been added to the bash completion, but many are still "hidden"

Upvotes: 4

Related Questions