Skip to content

Commands

-h/--help work on every command; -v/--version at the tool root.

hoplocate, open, and operate on repos from hop.yaml.

hop — locate, open, and operate on repos from hop.yaml. Grammar: hop <selection> <action> <selection> = a repo name (substring → fzf on ambiguity), a repo/worktree, a group name, or --all (every cloned repo). <action> = a builtin verb (cd, open, where), a batch verb (pull, push, sync), any PATH binary (git pull, code .), or a shell alias/function (p). Omit the action to cd into the selection. Getting started: 1. Run `hop config init` to create a starter hop.yaml. 2. Edit it to list your repos (each entry: name + git URL + parent dir). 3. For interactive use, install the shim: eval "$(hop shell-init zsh)" Cheat sheet: hop fzf picker, print selection hop <name> cd into the repo (shell function — needs `eval "$(hop shell-init zsh)"`) hop <name>/<wt> same, but rooted at <wt> (a worktree of <name> per `wt list --json`) hop <name> cd same — explicit verb form hop <name> where echo abs path of matching repo (or worktree, with /<wt> suffix) hop <name> open open the repo in an app (delegates to wt's menu; "Open here" cds the parent shell) hop <name> git pull run `git pull` with cwd = <name>'s repo dir (any PATH binary works) hop <name> code . open the editor in <name>'s repo dir (tool-form — runs in the parent shell) hop <name> p run the shell alias/function `p` in <name>'s repo dir hop <name> pull run `git pull` in the named repo (batch verb, selection-first) hop <name> push run `git push` in the named repo hop <name> sync auto-commit dirty tree, then `git pull --rebase` + `git push` hop <group> pull run `git pull` in every cloned repo of <group> hop --all pull run `git pull` in every cloned repo hop --all sync run sync in every cloned repo hop clone <name> git clone the repo if it isn't already on disk hop clone <url> ad-hoc clone: clone the URL, register it in hop.yaml, print landed path hop clone --all clone every repo from hop.yaml that isn't already on disk hop clone fzf picker, then clone if missing hop ls list all repos hop ls --trees list all repos with worktree summaries (fans out `wt list --json`) hop add <dir> register on-disk repos into hop.yaml (-r walks a tree, -p previews) hop rm [<name>] remove a repo from hop.yaml (fzf picker if no name) hop shell-init <shell> emit shell integration (zsh or bash). Use: eval "$(hop shell-init zsh)" hop config init bootstrap a starter hop.yaml hop config where print the resolved hop.yaml path hop config print print the resolved hop.yaml contents to stdout hop update self-update the hop binary via Homebrew hop -h | --help show this help hop -v | --version print version Notes: - `hop <name>` and `hop <name> cd` require shell integration (a binary can't change its parent shell's cwd). Without it, use: cd "$(hop <name> where)" - Tool-form (`hop <name> <tool> ...`) and `hop <name> open`'s "Open here" choice run in the parent shell via the shim. Scripts/CI that bypass the shim must use `hop <name> where` for path resolution and run tools themselves. - `pull`, `push`, `sync` accept a repo, a worktree, a group, or `--all` as the selection. `sync` is `pull --rebase` + `push` (linear history, no auto-resolve on conflict), auto-committing a dirty tree first. - A plural selection (`--all` or a group) accepts only `pull`/`push`/`sync` — cd, open, where, and arbitrary tools across many repos are refused. - On ambiguous or no-match queries, fzf opens prefilled with your query. - Config lives at ~/.config/hop/hop.yaml.

usage
  • hop [flags]
  • hop [command]
flags
flagtypedescriptioncopy
--allselect every cloned repo from hop.yaml (plural selection — use with pull/push/sync)
show raw -h output
hop — locate, open, and operate on repos from hop.yaml.

Grammar: hop <selection> <action>
  <selection> = a repo name (substring → fzf on ambiguity), a repo/worktree, a
                group name, or --all (every cloned repo).
  <action>    = a builtin verb (cd, open, where), a batch verb (pull, push,
                sync), any PATH binary (git pull, code .), or a shell
                alias/function (p). Omit the action to cd into the selection.

Getting started:
  1. Run `hop config init` to create a starter hop.yaml.
  2. Edit it to list your repos (each entry: name + git URL + parent dir).
  3. For interactive use, install the shim: eval "$(hop shell-init zsh)"

Cheat sheet:
  hop                       fzf picker, print selection
  hop <name>                cd into the repo (shell function — needs `eval "$(hop shell-init zsh)"`)
  hop <name>/<wt>           same, but rooted at <wt> (a worktree of <name> per `wt list --json`)
  hop <name> cd             same — explicit verb form
  hop <name> where          echo abs path of matching repo (or worktree, with /<wt> suffix)
  hop <name> open           open the repo in an app (delegates to wt's menu; "Open here" cds the parent shell)
  hop <name> git pull       run `git pull` with cwd = <name>'s repo dir (any PATH binary works)
  hop <name> code .         open the editor in <name>'s repo dir (tool-form — runs in the parent shell)
  hop <name> p              run the shell alias/function `p` in <name>'s repo dir
  hop <name> pull           run `git pull` in the named repo (batch verb, selection-first)
  hop <name> push           run `git push` in the named repo
  hop <name> sync           auto-commit dirty tree, then `git pull --rebase` + `git push`
  hop <group> pull          run `git pull` in every cloned repo of <group>
  hop --all pull            run `git pull` in every cloned repo
  hop --all sync            run sync in every cloned repo
  hop clone <name>          git clone the repo if it isn't already on disk
  hop clone <url>           ad-hoc clone: clone the URL, register it in hop.yaml, print landed path
  hop clone --all           clone every repo from hop.yaml that isn't already on disk
  hop clone                 fzf picker, then clone if missing
  hop ls                    list all repos
  hop ls --trees            list all repos with worktree summaries (fans out `wt list --json`)
  hop add <dir>             register on-disk repos into hop.yaml (-r walks a tree, -p previews)
  hop rm [<name>]           remove a repo from hop.yaml (fzf picker if no name)
  hop shell-init <shell>    emit shell integration (zsh or bash). Use: eval "$(hop shell-init zsh)"
  hop config init           bootstrap a starter hop.yaml
  hop config where          print the resolved hop.yaml path
  hop config print          print the resolved hop.yaml contents to stdout
  hop update                self-update the hop binary via Homebrew
  hop -h | --help           show this help
  hop -v | --version        print version

Notes:
  - `hop <name>` and `hop <name> cd` require shell integration (a binary can't change
    its parent shell's cwd). Without it, use:  cd "$(hop <name> where)"
  - Tool-form (`hop <name> <tool> ...`) and `hop <name> open`'s "Open here" choice run in
    the parent shell via the shim. Scripts/CI that bypass the shim must use
    `hop <name> where` for path resolution and run tools themselves.
  - `pull`, `push`, `sync` accept a repo, a worktree, a group, or `--all` as the
    selection. `sync` is `pull --rebase` + `push` (linear history, no auto-resolve on
    conflict), auto-committing a dirty tree first.
  - A plural selection (`--all` or a group) accepts only `pull`/`push`/`sync` —
    cd, open, where, and arbitrary tools across many repos are refused.
  - On ambiguous or no-match queries, fzf opens prefilled with your query.
  - Config lives at ~/.config/hop/hop.yaml.

Usage:
  hop [flags]
  hop [command]

Available Commands:
  add         register on-disk repos into hop.yaml (single dir, or -r to walk a tree)
  clone       git clone the resolved repo, an ad-hoc URL, or all missing repos with --all
  completion  Generate the autocompletion script for the specified shell
  config      config helpers (init, where, print)
  help        Help about any command
  ls          list all repos as aligned name/path columns
  rm          remove a registered repo from hop.yaml
  shell-init  emit shell integration (zsh or bash)
  update      self-update the hop binary via Homebrew

Flags:
      --all   select every cloned repo from hop.yaml (plural selection — use with pull/push/sync)

Use "hop [command] --help" for more information about a command.
hop addregister on-disk repos into hop.yaml (single dir, or -r to walk a tree)

Register on-disk repos into hop.yaml. By default, classifies just <dir> and — when it is a normal git repo with a remote — merges its URL into hop.yaml using the group convention (convention layout → the 'default' group; otherwise an invented group keyed off the parent dir basename). add writes by default. With -r/--recursive, walks <dir> for git repos (DFS, depth-bounded via --depth, symlink-following) and registers every one it finds. With -p/--print, renders the merge plan to stdout instead of writing (a dry-run, valid at both breadths). With -g/--group <name>, forces all discovered repos into the named group, auto-creating it if absent. A non-git directory is a no-op (a clear message, exit 0), not an error.

usage
  • hop add <dir> [flags]
flags
flagtypedescriptioncopy
--depthintmaximum DFS depth (only meaningful with -r; root counts as depth 0; must be >= 1) (default 3)
-g, --groupstringforce all discovered repos into the named group, auto-creating it if absent
-p, --printrender the merge plan to stdout instead of writing to hop.yaml (a dry-run)
-r, --recursivewalk <dir> for git repos (DFS) instead of classifying just <dir>
examples
  hop add ~/code/acme/widget    register one existing repo into hop.yaml
  hop add -r ~/code             walk ~/code and register every repo found
  hop add -r -p ~/code          preview the recursive plan without writing
  hop add -g vendor ~/forks/x   register into a forced (auto-created) group
show raw -h output
Register on-disk repos into hop.yaml.

By default, classifies just <dir> and — when it is a normal git repo with a
remote — merges its URL into hop.yaml using the group convention (convention
layout → the 'default' group; otherwise an invented group keyed off the parent
dir basename). add writes by default.

With -r/--recursive, walks <dir> for git repos (DFS, depth-bounded via --depth,
symlink-following) and registers every one it finds. With -p/--print, renders
the merge plan to stdout instead of writing (a dry-run, valid at both breadths).
With -g/--group <name>, forces all discovered repos into the named group,
auto-creating it if absent.

A non-git directory is a no-op (a clear message, exit 0), not an error.

Examples:
  hop add ~/code/acme/widget    register one existing repo into hop.yaml
  hop add -r ~/code             walk ~/code and register every repo found
  hop add -r -p ~/code          preview the recursive plan without writing
  hop add -g vendor ~/forks/x   register into a forced (auto-created) group

Usage:
  hop add <dir> [flags]

Flags:
      --depth int      maximum DFS depth (only meaningful with -r; root counts as depth 0; must be >= 1) (default 3)
  -g, --group string   force all discovered repos into the named group, auto-creating it if absent
  -p, --print          render the merge plan to stdout instead of writing to hop.yaml (a dry-run)
  -r, --recursive      walk <dir> for git repos (DFS) instead of classifying just <dir>
hop clonegit clone the resolved repo, an ad-hoc URL, or all missing repos with --all
usage
  • hop clone [<name> | <url> | --all] [flags]
flags
flagtypedescriptioncopy
--allclone every repo from hop.yaml that isn't already on disk
--groupstringtarget group for ad-hoc URL clone (only used with <url>) (default "default")
--namestringoverride the URL-derived name for the on-disk path (only used with <url>)
--no-addskip the hop.yaml write-back (only used with <url>)
--no-cdsuppress the printed path so the shell shim does not cd (only used with <url>)
show raw -h output
Usage:
  hop clone [<name> | <url> | --all] [flags]

Flags:
      --all            clone every repo from hop.yaml that isn't already on disk
      --group string   target group for ad-hoc URL clone (only used with <url>) (default "default")
      --name string    override the URL-derived name for the on-disk path (only used with <url>)
      --no-add         skip the hop.yaml write-back (only used with <url>)
      --no-cd          suppress the printed path so the shell shim does not cd (only used with <url>)
hop configconfig helpers (init, where, print)
usage
  • hop config
  • hop config [command]
show raw -h output
Usage:
  hop config
  hop config [command]

Available Commands:
  init        bootstrap a starter hop.yaml at the resolved write target
  print       print the resolved hop.yaml contents to stdout
  where       print the resolved hop.yaml path (regardless of file existence)

Use "hop config [command] --help" for more information about a command.
hop config initbootstrap a starter hop.yaml at the resolved write target
usage
  • hop config init
show raw -h output
Usage:
  hop config init
hop config printprint the resolved hop.yaml contents to stdout
usage
  • hop config print
show raw -h output
Usage:
  hop config print
hop config whereprint the resolved hop.yaml path (regardless of file existence)
usage
  • hop config where
show raw -h output
Usage:
  hop config where
hop lslist all repos as aligned name/path columns
usage
  • hop ls [flags]
flags
flagtypedescriptioncopy
--treeswt list --jsonlist worktrees per repo via wt list --json
show raw -h output
Usage:
  hop ls [flags]

Flags:
      --trees wt list --json   list worktrees per repo via wt list --json
hop rmremove a registered repo from hop.yaml

Remove a registered repo from hop.yaml. With no argument, pipes the registered repos through fzf and removes the selected entry's URL from its group. With a <name>, resolves it via the same match-or-fzf algorithm used by 'hop <name> where' and removes that entry directly — naming a repo prunes it even if its folder is already gone. Removal always targets a whole repo entry; any '/<worktree>' suffix on <name> is ignored (worktrees are not registry entries). Removing a group's last URL leaves the (now-empty) group as a placeholder, so it stays a valid 'hop clone --group' target. With --stale, the picker is pre-filtered to repos whose resolved path no longer exists on disk — the quick way to prune entries for repos you have deleted. --stale is a picker-scoping flag and cannot be combined with a <name>.

usage
  • hop rm [<name>] [flags]
flags
flagtypedescriptioncopy
--stalelimit the picker to repos whose resolved path no longer exists on disk
examples
  hop rm           pick any registered repo to remove
  hop rm widget    remove the repo matching 'widget' directly (no picker)
  hop rm --stale   pick among only the repos missing from disk
show raw -h output
Remove a registered repo from hop.yaml.

With no argument, pipes the registered repos through fzf and removes the
selected entry's URL from its group. With a <name>, resolves it via the same
match-or-fzf algorithm used by 'hop <name> where' and removes that entry
directly — naming a repo prunes it even if its folder is already gone. Removal
always targets a whole repo entry; any '/<worktree>' suffix on <name> is
ignored (worktrees are not registry entries).

Removing a group's last URL leaves the (now-empty) group as a placeholder, so
it stays a valid 'hop clone --group' target.

With --stale, the picker is pre-filtered to repos whose resolved path no longer
exists on disk — the quick way to prune entries for repos you have deleted.
--stale is a picker-scoping flag and cannot be combined with a <name>.

Examples:
  hop rm           pick any registered repo to remove
  hop rm widget    remove the repo matching 'widget' directly (no picker)
  hop rm --stale   pick among only the repos missing from disk

Usage:
  hop rm [<name>] [flags]

Flags:
      --stale   limit the picker to repos whose resolved path no longer exists on disk
hop shell-initemit shell integration (zsh or bash)
usage
  • hop shell-init <shell>
show raw -h output
Usage:
  hop shell-init <shell>
hop updateself-update the hop binary via Homebrew
usage
  • hop update [flags]
flags
flagtypedescriptioncopy
--skip-brew-updatebrew updateskip the internal brew update tap-metadata refresh (the version check and upgrade still run)
show raw -h output
Usage:
  hop update [flags]

Flags:
      --skip-brew-update brew update   skip the internal brew update tap-metadata refresh (the version check and upgrade still run)