Ramblings of an aging IT geek
← Ramblings of an aging IT geek
tooling

fzf, and the slow death of remembering exact filenames

How a single fuzzy finder reshaped my shell, my git workflow, and the way I navigate large codebases, with the keybindings and functions I actually use.

A mechanical keyboard lit beside a terminal

There's a small category of tool that doesn't add a feature so much as change how you hold the whole instrument. fzf is the clearest example I have. It's a fuzzy finder: you pipe it a list of things, you type a few characters, it narrows the list interactively, you pick one. That's the entire concept. And somehow that one idea, applied everywhere, has rewired how I use the terminal more than any shell or framework I've adopted in years.

The pitch is simple. I no longer remember exact names. Not filenames, not branch names, not the precise spelling of that script in ./scripts/ I wrote eight months ago. I remember a fragment, and fzf does the rest.

the three bindings that do most of the work

If you install fzf and source its shell integration, you get three keybindings out of the box, and these alone justify it:

  • Ctrl-T puts a fuzzy file picker into the current command line. Type vim , hit Ctrl-T, find the file, done.
  • Ctrl-R replaces the dismal default history search with a fuzzy one. This is the one I'd miss most. No more pressing up forty times.
  • Alt-C fuzzy-changes directory below the current one.

I lived on just these for a while and was already happier. But the real gains came from wiring fzf into the tools I use constantly.

git, made navigable

Git is full of long lists you have to know the names in: branches, commits, files. fzf turns all of them into a picker. Here's the branch switcher I use, lightly cleaned up:

fbr() {
  local branch
  branch=$(git branch --all | grep -v HEAD | sed 's/^[* ]*//;s|remotes/origin/||' | sort -u |
    fzf --preview 'git log --oneline --color=always {} | head -50') || return
  git switch "$(echo "$branch" | sed 's#remotes/[^/]*/##')"
}

The --preview window is the part people miss. As you move through the list, fzf runs a command against the highlighted item and shows the output in a side pane. So I'm not just picking a branch by name, I'm seeing its recent commits as I scroll. Picking a commit to fixup, browsing a stash, choosing a file to git add: all the same shape, all a list piped into fzf with a preview.

A terminal showing code and a fuzzy search interface

ripgrep plus fzf, for navigating code you don't know

The combination I reach for most when I'm dropped into an unfamiliar codebase is ripgrep feeding fzf, with a preview that shows the matching line in context. Search for a symbol, scroll the matches with the surrounding code visible, hit enter, and land in your editor on the exact line:

rg --line-number --no-heading --color=always "$1" |
  fzf --ansi --delimiter ':' \
      --preview 'bat --color=always --highlight-line {2} {1}' \
      --preview-window 'right:60%:+{2}-/2'

This replaced a whole category of "grep, squint, open file, scroll to line, repeat" with one interactive motion. It's the closest the terminal gets to a proper code-navigation pane, and it's a dozen lines of shell.

the bit I didn't expect

What surprised me wasn't any single function. It was that fzf lowered the cost of building tiny tools. Once "show the user a list and let them pick fuzzily" is a one-liner, you reach for it constantly. Pick a Docker container to attach to. Pick a Kubernetes pod to tail. Pick a process to kill. Pick an SSH host from your config. Each of these is five minutes to write and a small pleasure to use forever after.

fkill() {
  local pid
  pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}') || return
  echo "$pid" | xargs kill "${1:--TERM}"
}

The honest caveat is that none of this is free. These are functions you accumulate, and they live in your dotfiles, and on a fresh box without them you're suddenly clumsy. There's a small dependency you've taken on your own muscle memory. I've decided I'm fine with that, the same way I'm fine with depending on the existence of cd.

If you've seen fzf mentioned and filed it under "yet another shell toy", I'd gently push back. Install it, source the integration, and just use Ctrl-R for a week. The fuzzy history search alone is the most quietly useful change I've made to my shell in a long time, and the rest follows on its own.