"Magnifying Glass" by Birmingham Conservation Trust is licensed under CC BY 2.0 .
The Backstory#
I’ve written on fuzzy matching with fzf
before. I’ve covered adding tab
completion to an existing command, using
fzf to get a file preview windows
and combining tab completion and preview windows to improve an existing
command.
Those are helpful things to do and I use them all the time, but today I’d like
to cover a much simpler use case – a one-liner to allow you to use fuzzy
matching to navigate git
worktrees. If you’d like to read up on why you
may want to use worktrees in git
, I’ve covered that in 4 Strategies for
Context Switching in Git.
Just Show Me the Command#
You’ve heard enough from me by this point. Let’s try the command below. If
you’re playing along at home, you’ll need to be inside a git
repository.
Note: if you’re in a repository where you have not explicitly created a worktree, you’ll only get one result in the list, since git repositories by default exist in a worktree.
cd "$(git worktree list | fzf | awk '{print $1}')"
If you have more than one worktree in your repository, you should see something like this:
/Users/olaf/.worktree/Perl-Advent/oalders/santa-picks-nits c312df9 [oalders/santa-picks-nits]
/Users/olaf/.worktree/Perl-Advent/oalders/perlimports a8884db [oalders/perlimports]
>> /Users/olaf/Documents/github/perladvent/Perl-Advent 2a3d745 [oalders/new-index.html]
3/3 (0) ───────────────────────────────────────────────────────────────────────────────────────────────────
>
Once you begin typing, the matching begins:
/Users/olaf/.worktree/Perl-Advent/oalders/perlimports a8884db [oalders/perlimports]
/Users/olaf/Documents/github/perladvent/Perl-Advent 2a3d745 [oalders/new-index.html]
>> /Users/olaf/.worktree/Perl-Advent/oalders/santa-picks-nits c312df9 [oalders/santa-picks-nits]
3/3 (0) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
> nit
At this point a return
will cd
you to the worktree of your choice, or you
can opt out via ctrl-c
.
Let it Live in a Function#
To make this easier to use, you can store it in a function:
cd_worktree() {
cd "$(git worktree list | fzf | awk '{print $1}')"
}
If this is in your .bashrc
or some other place that gets sourced by your
environment, you can have access to this selector via the function name
directly at the command line:
$ cd_worktree
Or Put it in a Script#
This works too:
#!/bin/bash
set -eu -o pipefail
cd "$(git worktree list | fzf | awk '{print $1}')"
How About an alias?#
You might find a way to mash this into an alias
, but I should point out the following:
- The bash man page says that
For almost every purpose, shell functions are preferred over aliases
- You’ll likely have a linter complaining about a positional parameter in an alias. And yes, I realize that the
$1
here is anawk
thing rather than abash
thing, but my linter doesn’t know that.
Having said that, how you handle this is entirely up to you. If someone tells that using an alias means you’re wrong, you can kindly tell them to get stuffed, because there’s certainly more than one way to do it.
How it Works#
Let’s break this down. Basically there are 4 things happening here:
cd "$(git worktree list | fzf | awk '{print $1}')"
git worktree list
is being called- All of the output from
git worktree list
is piped directly tofzf
. At this point nothing happens until there is some input from the keyboard - Once there is a carriage
<return>
, the entire selected line is handed off toawk
, which splits the line on spaces and returns the first element in the list ($1
). That element is the path to the root directory of the worktree. - The worktree path is provided to the
cd
command and now you are on your way
Build Something Fun#
What I like about this example is that it’s not particularly complicated, but
it has enough moving parts that it merits some discussion. You could build
something similar for switching between git
branches, tmux
sessions or
something way better that I haven’t even thought of.
Because it fits on one line you can even keep it as a handy snippet that you copy/paste, if you don’t feel like making shell functions available or putting the one-liner into a script or whatever.
I hope you have fun with this. Please let me know if you build something you’d like to share with me.