Since 1999

 

2 minutes estimated reading time.

How to hide .gitignored Files from fzf.vim

Alex Piechowski

Messy Phoenix Fuzzy Finder

Fuzzy finders find files that almost no developer would intentionally find via a fuzzy finder from paths such as node_modules/, deps/, and dist/. These tend to get in the way of the true power of fuzzy file searching and ignoring these individually can be a pain. There are also files like .circleci/config.yml, .gitignore, and .rubocop.yml that are opened often enough to be included in the result set.

Luckily when working in a git repository, developers typically only care about the files they commit. When using fzf.vim, this technique returns files based on the git tree leaving out irrelevant files, including the hidden files that were shown before.

TL;DR: The Solution

" fzf file fuzzy search that respects .gitignore
" If in git directory, show only files that are committed, staged, or unstaged
" else use regular :Files
nnoremap <expr> <C-p> (len(system('git rev-parse')) ? ':Files' : ':GFiles --exclude-standard --others --cached')."\<cr>"

How does it work?

This single line provides an intelligent fallback whilst trying to be as efficient as possible.

It checks if we’re on a git repo by executing git rev-parse (<1ms) to check if vim is running within in a git repo. If the length of this command is > 0, which would be the case if it spat out the fatal: not a git repository error, then we know we’re not in a git repo and we utilize :Files instead.

If git rev-parse doesn’t return anything, we know we’re in a git repo and can utilize fzf.vim’s :GFiles method which fuzzy finds utilizing git ls-files. Utilizing the following flags, this expression specifies the files we want more specifically:

  • --exclude-standard: Add the standard Git exclusions: .git/info/exclude, .gitignore in each directory, and the user’s global exclusion file.
  • --others: Show other (i.e. untracked) files in the output
  • --cached: Show cached (AKA staged) files in the output (default)

I use ag -l as my fzf command to be faster… How much slower is this?

It’s not! So long as you’re inside a repo, this will result in a much faster fuzzy finder load.

In a repo with ~5k files returned by git ls-files, we experienced the following:

  • git rev-parse consistently takes <1ms to execute
  • ag -l takes on average approximately 250ms to complete
  • git ls-files takes on average approximately 16ms to complete

This means that when control + p is executed outside of a git repo, it is less than 1ms slower than before, but if you’re inside a repository, it’s over 16x faster!