Checkout git branches faster with fzf
October 7, 2020 ‐ 3 min read
In large git repo's I find myself sometimes lost in switching branches. For this project I work on using Bitbucket we use branch names starting with a JIRA issue number. This makes relying on Tab-completion harder. I ain't got time to remember JIRA issue numbers.
This is where fzf
comes in, a fuzzy finder for the command-line. You can find the GitHub repo here.
You can pipe lines to fzf
and it gives you an interactive input prompt you can use to filter.
$ git branch | fzf
> juice
29/29
> XY-8435-create-juice-model
XY-5193-fix-juice-form-fields
The above example just outputs the branch name you select. In this case it filtered the branches that were listed using git branch
on the keyword juice
.
In order for this to be somewhat useful you need to combine it with a git checkout
. In order to do so you can use the following. Where the output of $(git branch | fzf)
is used as argument to the checkout
subcommand.
$ git checkout $(git branch | fzf)
Switched to branch 'master'
So this already does the job. As you see above you can switch branches like this. There is a problem with this however and is has to do with the outputs of git branch
.
$ git branch
develop
* master
As you see the current branch is marked with an asterisk(*
). Eventhough it is unlikely I would want to try to switch my current branch. Actually I would never want that. But just to make it prone to typo's, lets fix it.
$ git checkout $(git branch | fzf)
error: pathspec 'master' did not match any file(s) known to git
If I would select master
, my current branch, in fzf
it would give me the error shown above. Since the output of fzf
contains the asterisk too. See the snippet bellow. Where I selected master in fzf
.
$ git branch | fzf
* master
So we have to get the branch names in some other way to not have the asterisk showing up. In git we can use a lesser known, for-each-ref
command and format the output as follows.
$ git for-each-ref refs/heads/ --format='%(refname:short)'
master
develop
I can use that command as a substitute for git branch
. If I now try to switch to my current branch I get a more appropriate message.
$ git checkout $(git for-each-ref refs/heads/ --format='%(refname:short)' | fzf)
Already on 'master'
Your branch is up to date with 'origin/master'
Cool, that works too! So we are finished but it turned into one hell of a command which I don't plan on typing out ever. Instead I created a separate script.
For me this script is at ~/Code/bin/interactive-checkout
, this works for me because I have the directory ~/Code/bin
added to my path.
The script interactive-checkout
has the following contents.
#!/bin/bash
git checkout $(git for-each-ref refs/heads/ --format='%(refname:short)' | fzf)
Now I can use interactive-checkout
as a command instead of git checkout $(git for-each-ref refs/heads/ --format='%(refname:short)' | fzf)
and I can potentially bind it to an alias as well.
Don't forget to make the script executable with chmod
:-).