Navigating a sea of repos
04 Jul 2020From both work and personal projects, I have lots (at the time of writing, 182) repositories cloned on my laptop. Most of these are repositories that I contribute to, though some are other code bases that I’ve cloned to be able to search more effectively with command line tools.
To help organise them in a sane way, I keep them in a directory structure that mirrors their URLs when cloned from GitHub, Bitbucket or GitLab. For example, they look like:
- ~/src/github.com/acroz/pylivy
- ~/src/bitbucket.org/acroz/other-repo
- ~/src/gitlab.com/organisation/group/subgroup/repo
This works well, and helps to find repositories that I know are stored in a particular Bitbucket organisation, for example, but works less well when I’m less sure of that repo’s location. Even when I do know the location, there’s still often a lot of bashing the tab key to complete nested directories.
To save time with this, I’ve set up a function in my shell that fuzzily matches the git repositories. This glues together 3 parts:
- Generate a list of all repos with
find
or similar - Fuzzily match on this list of repos with
fzy
- Change directory to the selected repo
Old solution with find
Prior to using GitLab repositories, I used the fact that all repositories were
exactly two levels below ~/src
to generate the list of repositories:
find ~/src -type d -mindepth 2 -maxdepth 2
However, since GitLab can have nested organisations, the depth of the
repository root relative to ~/src
can no longer be guaranteed. I was able to
generate a find
command that would identify git repositories using the fact
that they contain a .git
directory, but it was really slow because it’s
searching the contents of all the repositories when it doesn’t need to:
find ~/src -type d -name .git | sed 's/\/\.git$//g'
On my my current source directory, this takes 27 seconds to run!
New solution: git-find-repos
To more efficiently search my local directories, I wrote
a simple CLI tool that does a recursive search of a
directory, printing out git repositories. As it’s able to stop traversing down
a directory tree as soon as it encounters a .git
directory, it’s much faster
(0.26 seconds instead of 27).
You can check out git-find-repos
for yourself on GitHub.
Installation is easy with pip
or pipx
:
pipx install git-find-repos
By default, git-find-repos
searches the current directory recursively.
Alternatively, you can specifiy a particular path:
git-find-repos ~/src
You can also use git-find-repos
as if it were a subcommand of git
(thanks
to my colleague Víctor Zabalza for this suggestion):
git find-repos ~/src
Putting it all together
With git-find-repos
, I’m able to put together my convenience shell function
as desired. In my .zshrc
, I define the following function:
function repo {
initial_query=$1
dest=$(git find-repos ~/src | fzy -q "$initial_query" -l 20) && cd "$HOME/src/$dest"
}
Now, all I need to do to navigate to a repo is run repo
in the shell, type
enough of the name for it to match with fzy
, then hit enter. If a match is
found, the repo
function will change my directory there.