Docs

Reference

How to do things with gm, and what each command, key and setting does. To install it, seeInstall.

Finder

Ctrl-G in the shell (after gm shell) or gm opens it. The best match is the bottom row, next to the prompt; details of the selected row are on the right. While gm waits on git or GitHub, the line under the prompt says what it is waiting on.

Lists

ListOpen withShowsEnter
RepositoriesCtrl-G in the shell, or gmEvery repository under every rootGo there
WorktreesCtrl-WWorktrees of the selected repositoryGo there
BranchesCtrl-LLocal branches, and remote ones with no local branchGo to its worktree, creating it if needed
Pull requestsCtrl-JOpen pull requests, drafts marked [draft]Go to its worktree, creating it with gh pr checkout --worktree if needed
IssuesCtrl-[Open issuesOpen the issue's detail panel: q back, ↑↓ scroll, Ctrl-B browser, Ctrl-Y copy the URL

Keys

KeyAction
typeFilter the list
↑ ↓ / Ctrl-P Ctrl-NMove the cursor; PgUp PgDn move a screen
EnterGo to the selected row (gm prints its path and the shell cds there). With a command typed, run it
Ctrl-W Ctrl-L Ctrl-JOpen the worktree / branch / pull request list. The same key goes back to the repositories
Ctrl-[Open the issue list; the same key goes back to the repositories. Its byte is Esc, so at the repositories, with nothing to undo, it opens the issue list instead of quitting — Ctrl-C always quits
Ctrl-Alt-BOpen the repository's remote in a browser
TabAccept the command completion shown after the cursor
EscUndo one step: back to the repositories, clear the query, clear /dirty /unpushed, then (unless the issue list owns it, above) quit
Ctrl-GSame as Esc, but never quits
Ctrl-CQuit at once

Ctrl-W Ctrl-L Ctrl-J Ctrl-[ Ctrl-Alt-B can be changed: see Key bindings.

Slash commands

CommandActionWorks in
/get [flags] <repo>Clone (runs gm get) and go to itAll
/create [--ssh] <repo>Create a new repository with origin set (--ssh: SSH URL)Repositories
/create <branch>Check the branch out as a worktree; a new branch starts from HEADWorktrees, branches, PRs
/removeRemove the selected repository with its worktrees, or the selected worktree and its merged branch. Never the main worktreeRepositories, worktrees
/expire <days>dRemove worktrees whose HEAD has not moved for that long, and their merged branchesWorktrees
/dirty /unpushedToggle a filter: only repositories with uncommitted changes / unpushed commits, counting their worktrees. Both on: both must hold. Switching one on scans againRepositories
/worktrees /branches /prs /issues /browseSame as Ctrl-W Ctrl-L Ctrl-J Ctrl-[ Ctrl-Alt-BAll
/helpShow the command listAll

Commands

CommandDoes
gmOpen the finder; print the chosen path
gm get <repo>...Clone (alias clone)
gm list [<query>]Print repositories (alias ls)
gm statusList uncommitted and unpushed work
gm create <repo>Start a new repository (alias new)
gm remove <repo>...Remove repositories and their worktrees (alias rm)
gm wt create|remove|expireManage worktrees from scripts
gm migrate <dir>...Move existing clones into the tree
gm root [--all]Print the root(s)
gm shell <fish|zsh|bash>Print the shell key binding
gm version, gm helpVersion, usage. -h after a subcommand lists its flags

<repo> to clone or create is a URL or a shorthand: see Repository references.remove and wt take a query instead: an exact name, user/repo orhost/user/repo, else a substring; more than one match is an error listing them.

gm get [flags] <repo>...

Clones each repository under the first root, submodules included. One already cloned is skipped unless -u is given.

FlagEffect
-u, --updateUpdate a repository already cloned instead of skipping it
--sshClone over SSH
--shallowgit clone --depth 1
-b <branch>Clone that branch only
--no-recursiveSkip submodules (cloned by default)
-s, --silentQuiet git clone
-l, --lookAfterwards, start a shell inside the repository

-u fetches and fast-forwards the checked-out branch. It never merges: a dirty tree or a diverged branch is left alone, with a skip line saying why.

gm list [flags] [<query>]

Prints host/user/repo for every repository whose path contains the query (case-sensitive).

FlagEffect
-p, --full-pathAbsolute paths
-e, --exactThe query must equal the name, user/repo, or host/user/repo
--uniqueThe shortest name no other repository shares: gm, else jedipunkz/gm, else the full path

gm status [flags]

Lists repositories and worktrees with uncommitted changes or unpushed commits, e.g.3 changed files, 2 unpushed. It never fetches, so it works offline; behind counts are as of the last fetch.

FlagEffect
--dirtyOnly rows with uncommitted changes
--unpushedOnly rows with unpushed commits (with --dirty: both)
-aAlso rows that are clean and in sync
-p, --full-pathAbsolute paths

gm create [--ssh] <repo>

Makes the directory under the first root, runs git init, sets origin (SSH with--ssh), and prints the path. Refused if the repository already exists or the directory is not empty.

gm remove [--dry-run] [-y] <repo>...

Removes each repository and every worktree checked out of it. Before asking, it lists what would be lost: uncommitted changes in the repository and in each worktree.

FlagEffect
--dry-runShow what would happen, change nothing
-yDo not ask for confirmation

gm wt create | remove | expire

The finder's worktree actions, for scripts. remove and expire take --dry-run and -y.

CommandEffect
gm wt create <repo> <branch>Check the branch out as a worktree (new branches start from HEAD); prints its path
gm wt remove <repo> <branch>Remove that worktree, then its branch if merged. Never the main worktree
gm wt expire <repo> <days>dRemove worktrees whose HEAD has not moved for that many days, and their merged branches. Ones with uncommitted changes are kept

gm migrate [--dry-run] [-y] [-r] <directory>...

Moves existing clones to the path their origin says, asking for each, and repairs their worktrees.-r searches each directory for repositories instead and skips the ones it cannot move (noorigin, destination exists, already cloned under another root, a worktree or submodule).

gm root / gm shell / gm version

ShellAdd to
fishgm shell fish | source in ~/.config/fish/config.fish
zsheval "$(gm shell zsh)" in ~/.zshrc
basheval "$(gm shell bash)" in ~/.bashrc

Scripting

Where repositories go

Repository references

A <repo> to clone or create becomes a URL, and its host/user/repo is the directory under the root.

Written asDirectory
https://github.com/u/rgithub.com/u/r
git@github.com:u/r.gitgithub.com/u/r
example.com/u/rexample.com/u/r (over https)
u/rgithub.com/u/r
rgithub.com/<you>/r: git config github.user, else $USER

Directory layout

~/ghq/github.com/jedipunkz/gm/                            repository
~/ghq/.worktrees/github.com/jedipunkz/gm/feat/login       worktree of branch feat/login
~/ghq/.worktrees/github.com/jedipunkz/gm/.forks/bob/main  worktree of a pull request from bob's fork

Configuration

gm.toml

~/.config/gm/gm.toml (or $XDG_CONFIG_HOME/gm/gm.toml), optional. Every key is optional too. A typo, an unknown key or a wrong type is an error naming the file, so a setting is never silently ignored.

gm.toml
root         = "~/ghq"         # or ["~/ghq", "~/src"], searched in order
theme        = "tokyonight"
launch_key   = "ctrl-g"
worktree_key = "ctrl-w"
branch_key   = "ctrl-l"
pr_key       = "ctrl-j"
issue_key    = "ctrl-["
remote_key   = "ctrl-alt-b"
KeyDefaultMeaning
root~/ghqWhere repositories live; a list is searched in order, the first gets new clones
themetokyonightThe finder's colors
launch_keyctrl-gThe shell key that opens gm
worktree_keyctrl-wFinder: worktree list
branch_keyctrl-lFinder: branch list
pr_keyctrl-jFinder: pull request list
issue_keyctrl-[Finder: issue list
remote_keyctrl-alt-bFinder: open the remote in a browser

Roots

The first source that is set wins, so an existing ghq setup works untouched:

#Source
1$GM_ROOT (colon-separated)
2root in gm.toml
3git config gm.root (every value)
4$GHQ_ROOT (colon-separated)
5git config ghq.root (every value)
6~/ghq

~ expands to your home directory; every root must be absolute. New clones go to the first root; all roots are listed and searched.

Key bindings

Write a chord as Ctrl, optionally Alt and Shift, plus one letter: ctrl-g, ctrl-alt-b(Ctrl+Alt+B, c-a-b and ^b also work). An invalid chord is an error.

ChordWorks in
ctrl-<letter>Every terminal
ctrl-alt-<letter>Nearly every terminal
ctrl-shift-<letter>Only terminals with the Kitty keyboard protocol (Ghostty, kitty, WezTerm, foot, recent Alacritty); elsewhere it arrives as ctrl-<letter>

Themes

tokyonight catppuccin-frappe catppuccin-latte catppuccin-macchiato catppuccin-mocha dracula kanagawa-wave rose-pine solarized-dark solarized-light

The default is tokyonight. See the palettes on the home page.

Ranking

Requirements and environment

FilePurpose
~/.config/gm/gm.tomlSettings ($XDG_CONFIG_HOME/gm/ if set). Optional
~/.local/state/gm/frecency.jsonVisit log ($XDG_STATE_HOME/gm/ if set). Delete it to reset the ranking
<root>/.worktrees/Worktrees
VariableEffect
GM_ROOTRoots, colon-separated; overrides every other setting
GHQ_ROOTRoots, colon-separated; used when gm has no setting of its own
XDG_CONFIG_HOME, XDG_STATE_HOMEWhere gm.toml and the visit log live
GM_LOOKSet by gm get -l in the shell it starts: the repository's path