cd /news/developer-tools/hop-cli-tool-for-jumping-around-work… · home topics developer-tools article
[ARTICLE · art-95749] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Hop: CLI tool for jumping around worktrees

Syntaf released hop v0.1.0, a CLI tool that searches all git repositories under a user's code directory and jumps to the worktree holding a given branch, with tiered matching, tab completion, and an installer that configures zsh. The tool requires zsh, bash 3.2+, git, and curl, and supports pinning versions via HOP_REF.

read5 min views1 publishedAug 13, 2026
Hop: CLI tool for jumping around worktrees
Image: source

Jump to the git worktree holding a branch.

If you keep a lot of worktrees, finding the one holding a given branch means running git worktree list

in repo after repo — and the worktree's directory name usually isn't the branch name. hop

searches every repo you have at once and cd

s you there.

$ hop login-fix
  repo    webapp
  branch  feature/login-fix
  status  in sync with origin, no tracked changes
  path    ~/Code/webapp/.claude/worktrees/pr-4821-review
curl -fsSL https://raw.githubusercontent.com/Syntaf/hop/main/install.sh | bash

If you would rather not pipe a script into a shell — reasonable — download it, read it, then run it. The &&

matters: without it a failed download still gets executed.

curl -fsSL https://raw.githubusercontent.com/Syntaf/hop/main/install.sh -o hop-install.sh \
  && less hop-install.sh && bash hop-install.sh && rm hop-install.sh

Or from a checkout, which skips the download entirely:

git clone https://github.com/Syntaf/hop.git && cd hop && ./install.sh

The installer asks where you keep your repos, guessing from the conventional directories (~/Code

, ~/src

, ~/Projects

, …) by counting git repos in each:

hop-install: which directory holds your git repos? [~/Projects]

Press Enter to take the guess, or type a path (~

works). It writes that as HOP_CODE_ROOT

in your .zshrc

. To skip the question — for a scripted or unattended install — set it yourself:

curl -fsSL https://raw.githubusercontent.com/Syntaf/hop/main/install.sh | HOP_CODE_ROOT=~/src bash

With no terminal to prompt on, it uses the guess and tells you how to change it, rather than hanging.

Then open a new shell. The installer puts hop-resolve

in ~/.local/bin

, hop.zsh

in ~/.config/hop

, and adds a short block to your .zshrc

. It is idempotent — re-run it to upgrade, and it will leave an existing config alone rather than re-asking. To uninstall, delete those two files and that block.

Requires zsh, bash 3.2+ (macOS stock is fine), git, and curl.

Pin a version with HOP_REF

, and change where things land with HOP_BIN_DIR

/ HOP_CONF_DIR

:

curl -fsSL https://raw.githubusercontent.com/Syntaf/hop/main/install.sh | HOP_REF=v0.1.0 bash

HOP_REF

is what pins the version — fetching install.sh

from a tag URL alone does not, since the script then fetches its payload from main

. Note also that raw.githubusercontent.com

caches for a few minutes, so an install run immediately after a push may get the previous commit.

hop <query>       cd into the matching worktree (prompts when ambiguous)
hop               list every worktree it can find
hop -l <query>    list matches without cd'ing
hop -p <query>    print the path only:  code "$(hop -p my-branch)"
hop -h            full help

You never name a repo — every repo under ~/Code

is searched at once. A repo name is just an optional extra word to narrow things down: hop webapp login-fix

. Tab completion covers branch and worktree names.

Matching runs in tiers, best tier wins, and ties prompt you to pick rather than guessing:

tier matches example
1 exact branch claude/fix-thing
2 exact branch leaf fix-thing
3 exact worktree directory pr-4821-review
4 branch substring fix-th
5 worktree directory substring 4821
6 every word appears somewhere webapp alice session

Worktrees in the repo you're standing in sort first.

When no worktree holds the branch, hop

looks for the branch itself — local branches with no worktree, plus any remote-tracking ref already fetched — and offers to make one:

$ hop session-timeout
hop: no worktree holds alice/4821-session-timeout — it is a local branch in webapp.
     create a worktree at ~/Code/webapp/.claude/worktrees/alice+4821-session-timeout? [y/N]

Remote-only branches are fetched first and the new local branch is set to track them. Nothing is created without a y/N

. If the branch is so new that no remote-tracking ref exists, hop

offers to fetch the repo you're standing in, or you can name it: hop <repo> <branch>

.

New worktrees land in <repo>/.claude/worktrees/<branch>

, with /

in the branch name written as +

. That's where Claude Code puts its worktrees; if you keep yours elsewhere, hop

still finds them (it asks git, not the filesystem), it just creates new ones there.

variable meaning
HOP_CODE_ROOT
where to scan for repos; set by the installer (default ~/Code )
HOP_CACHE_TTL
seconds to cache the scan (default 0 = always fresh)
HOP_BANNER
0 , off or no to skip the arrival block
NO_COLOR
honoured; colour is also dropped when piped

Repos are found by looking for .git

one and two levels below HOP_CODE_ROOT

— so ~/Code/myrepo

and ~/Code/scratch/myrepo

both work.

A few decisions worth knowing, since they're deliberate:

Ambiguity always prompts. Two repos with the same branch name give you a numbered picker. Non-interactive callers get the candidate list and a non-zero exit instead of a silently-chosen first match.Untracked files are not counted.status

reports tracked changes only, because scanning for untracked files costs ~2s in a large monorepo versus ~0.1s without. That's why it says "no tracked changes" rather than "clean".Registered-but-deleted worktrees are flagged, not skipped, with thegit worktree prune

command to fix them.The scan is fresh by default. It's one parallelgit worktree list

per repo, ~0.15s across 30 repos. SetHOP_CACHE_TTL

if you want it cached; a cache miss re-scans before reporting failure, so a just-created worktree is never invisible.

A process can't change its parent shell's directory, so hop

is a zsh function wrapping hop-resolve

. The resolver prints a path on stdout and everything else on stderr, which is what makes hop -p

composable.

Bash users: hop-resolve

itself is bash and works fine, but the hop

function is zsh-only. A bash wrapper would be a short addition — it isn't written yet.

── more in #developer-tools 4 stories · sorted by recency
── more on @syntaf 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/hop-cli-tool-for-jum…] indexed:0 read:5min 2026-08-13 ·