The finder is built in
No ghq list | fzf | cd pipeline to assemble. The best match is the row at the bottom, next to the prompt, so the usual choice costs zero keystrokes.
ghq-style repository manager · built-in fuzzy finder
gm clones into one predictable host/user/repo tree, and Ctrl+G takes you to any of them — ranked by how well they match and how often you go there.
brew install jedipunkz/gm/gmLive demo with sample data — type to filter, ↑↓ to move, Enter to jump,/help for commands, and click ctrl-w for worktrees. The ranking is the same algorithm gm uses.
Why gm
An existing ghq tree works untouched. gm adds the parts you would otherwise glue together yourself.
No ghq list | fzf | cd pipeline to assemble. The best match is the row at the bottom, next to the prompt, so the usual choice costs zero keystrokes.
A fuzzy score first — a literal substring in the repository name beats letters scattered across the path — then frecency to break ties.
Path, remote, branch, working-tree status, visit count and the last three commits with their refs, so similar clones are easy to tell apart.
Ctrl-W swaps the list for the git worktrees of the repository under the cursor. /create <branch> checks one out without leaving the finder.
Roots, theme and key bindings live in gm.toml. $GHQ_ROOT and ghq.root are still honored, so an existing ghq tree needs no migration.
A new repository gets git init and its origin remote in one step — something ghq leaves to you.
Not implemented, deliberately: Mercurial / Subversion / Darcs cloning (they are still listed), bare clones, partial clones, parallel import, --vcs, and per-URL ghq.<url>.root roots.
Get started
Homebrew on macOS or Linux downloads a prebuilt binary; no Go needed.
brew install jedipunkz/gm/gmOr build from source with Go 1.25 or newer:
go install github.com/jedipunkz/gm@latestgm prints the chosen path, so it composes with $(...). One line in your rc file turns that into a cd on Ctrl+G.
gm shell fish | sourceeval "$(gm shell zsh)"eval "$(gm shell bash)"Clones land under the root; press Ctrl+G anywhere to jump.
gm get jedipunkz/gm
# then press Ctrl-G and type gmRequirements: git on $PATH, and a true-color terminal for the themes to look as intended.gm version says which version you have.
Usage
Ctrl+W swaps the repository list for the git worktrees of the repository under the cursor, and swaps it back. Going back keeps the query, the cursor and the highlights as they were.
| Key | Repository list | Worktree list |
|---|---|---|
| any character | Filter | Filter |
| ↑ / Ctrl-P | Move up | Move up |
| ↓ / Ctrl-N | Move down | Move down |
| Enter | Print the repository path and exit | Print the worktree path and exit |
| Ctrl-W | Show the worktrees of the selected repository | Back to the repositories |
| Ctrl-Alt-B | Open the remote in a browser | Open the remote in a browser |
| Ctrl-G | — | Back to the repositories |
| Esc | Clear the query, then the filter, then quit | Back to the repositories |
| Ctrl-C | Quit without printing | Quit without printing |
Everything else is ordinary text editing (Ctrl-A, Ctrl-E, Ctrl-U…), exceptCtrl-W, which no longer deletes the word before the cursor. Esc undoes one layer of narrowing at a time — the worktree list, then the query, then the filter — and only quits once there is nothing left to undo.
A / at the start of the input types a command instead of a filter; Tab completes it./create and /remove ask first, in a panel over the list, and do the work without leaving the finder.
| Command | What it does |
|---|---|
/help | Show the command list; q or Esc closes it |
/dirty | Show only repositories with uncommitted work; Esc shows all |
/create <repo> | Create a repository, after asking; adds it to the list |
/create <branch> | In the worktree list: check that branch out as a worktree |
/get <repo> | Same as gm get, then go to the clone |
/remove | Remove the selected repository, or worktree, after asking |
/worktrees | Same as Ctrl-W |
/remote | Same as Ctrl-Alt-B |
The branch name is the only thing to type. /create <branch> starts the branch fromHEAD if it does not exist yet. The leading dot keeps worktrees out of the repository list: the walk never descends into a dotted directory. The main worktree cannot be removed from the worktree list.
~/gm/github.com/jedipunkz/gm/ the repository
~/gm/.worktrees/github.com/jedipunkz/gm/feat/login<repo> accepts a full URL, git@host:user/repo.git, host/user/repo,user/repo, or a bare repo (resolved against git config github.user).
| Command | What it does |
|---|---|
gm | Open the fuzzy finder; print the selected path |
gm get [-u] [-p] [--shallow] [-b <branch>] [-s] [-l] <repo>... | Clone into the tree; -u updates an existing clone |
gm list [-p] [-e] [--unique] [<query>] | List repositories (-p full paths, -e exact match, --unique shortest unambiguous name) |
gm status [--dirty] [--unpushed] [-a] [-p] | List every repository and worktree with uncommitted or unpushed work; never fetches |
gm remove [--dry-run] [-y] <repo>... | Remove a repository and its worktrees after confirming, pruning empty parents (gm rm also works) |
gm create [-p] <repo> | Create and git init a repository with origin already set |
gm wt <create|remove> [-y] <repo> <branch> | Add or remove a worktree from a script; the finder is better for doing it by hand |
gm migrate [--dry-run] [-y] [-r] <dir>... | Move an existing clone into the tree, using its origin remote; -r searches the directory |
gm root [--all] | Print the root directory |
gm shell <fish|zsh|bash> | Print the Ctrl-G binding |
gm version | Print the installed version |
Configuration
~/.config/gm/gm.toml (or $XDG_CONFIG_HOME/gm/gm.toml). A file that cannot be parsed, or that holds a key gm does not know, is an error rather than a file half ignored.
root = "~/ghq" # or ["~/ghq", "~/src"], searched in order
theme = "tokyonight"
launch_key = "ctrl-g" # the shell key that opens gm
worktree_key = "ctrl-w" # the finder key that lists worktrees
remote_key = "ctrl-alt-b" # the finder key that opens the remoteThe first one set wins, so an existing ghq tree works untouched.
$GM_ROOTroot in gm.tomlgit config --get-all gm.root$GHQ_ROOTgit config --get-all ghq.root~/ghqlaunch_key is the chord gm shell binds and must be a plain Ctrl chord;worktree_key and remote_key are the finder's own and also take alt andshift. Ctrl is written ctrl-, ctrl+, c- or ^. After changing launch_key, re-run gm shell <shell>.
| Chord | Reaches gm |
|---|---|
ctrl-<letter> | Everywhere |
ctrl-alt-<letter> | Nearly everywhere: Alt is sent as an ESC prefix |
ctrl-shift-<letter> | Only with the Kitty keyboard protocol — Ghostty, kitty, WezTerm, foot, recent Alacritty |
Set theme in gm.toml. An unknown name is an error listing the valid ones. The palettes below are read from gm's source when this site is built.
Ranking
Typing filters by fuzzy match, scored so that a literal substring beats a subsequence pieced together from elsewhere, and the repository name counts for more than the user name. The host is shared by nearly every repository, so matches there cost points instead of earning them.
Frecency only breaks ties between equally good matches. Visits are recorded in$XDG_STATE_HOME/gm/frecency.json (default ~/.local/state/gm/frecency.json); delete it to start over.
| Last visit | Score = visits |
|---|---|
| within the last hour | × 4 |
| within the last day | × 2 |
| within the last week | × 0.5 |
| older | × 0.25 |