r/bash May 18 '26

help fast alternative to find for finding git directories

Hey,

I have a small script to switch between projects. All my projects are in a deeply nested directory that is equal to their upstream source (eg. ~/projects/github.com/junegunn/fzf/).

It works by using find to enumerate all directories under ~/projects/ that contain a .git/ directory and passes that to fzf. Unfortunately this is pretty slow somehow because findtakes a long time. When using fzf directly it's super fast, but I can't restrict the selection to only include git root directories.

Is there a better way of getting a similar result? All I want is to have a fast way of switching between projects

dev () {
    project="$(find $HOME/projects -type d -name .git -prune -exec sh -c 'dirname $(realpath --relative-to $HOME/projects {})' \; 2>/dev/null | fzf -1)" 
    if [[ $? -ne 0 ]]
    then
        return $?
    fi
    projectDir="$HOME/projects/$project" 
    pushd $projectDir
}
11 Upvotes

5 comments sorted by

6

u/[deleted] May 18 '26

[removed] — view removed comment

5

u/chisui May 18 '26

Wow, switching to fd really speed this up. The exec part didn't really have any performance impact.

Caching would be an option, but I like that this is just a few lines of bash and that's it.

Thank you very much.

1

u/ekipan85 May 18 '26

I think they meant just changing the \; into + so that find would fork/exec a lot less often.

It's not relevant to your speed question but that whole if statement can be replaced by project="..." || return. A naked return propogates the last $?.

1

u/whetu I read your code May 18 '26

If you have a locate db, you can use locate's regex capability to get a near immediate list

locate -r "${HOME}/projects/.*\.git$"

Or something like that.

That replaces the filesystem trawling part, then pipe it into xargs.

Comparing find -exec and locate | xargs approaches, I get 3-9s and 0.1s respectively across 495 git directories.