ghqcd
v0.1.6
Published
Pick a ghq repository with fzf and cd into it.
Maintainers
Readme
ghqcd
Pick a ghq repository with fzf and cd into it.
$ ghqcd
repo>
▌ /Users/you/ghq/github.com/you/api
/Users/you/ghq/github.com/you/web
/Users/you/ghq/git.example.com/team/infra
╭───────────────────────────────────────╮
│ 8f2c1a9 Fix the retry budget │
│ 3b7d004 Bump the client │
╰───────────────────────────────────────╯
$ pwd
/Users/you/ghq/github.com/you/apiInstall
npm install -g ghqcdThen add the shell integration:
# zsh — ~/.zshrc
eval "$(command ghqcd --init zsh)"
# bash — ~/.bashrc
eval "$(command ghqcd --init bash)"
# fish — ~/.config/fish/config.fish
command ghqcd --init fish | sourcecommand matters: each tool defines a shell function with its own name, so on a
second source ~/.zshrc the function would answer, capture the --init output
and try to cd into it. command skips functions and goes to the binary.
Reload the shell and ghqcd moves it.
Prefer a different name? eval "$(ghqcd --init zsh --cmd gcd)" gives you gcd.
Without installing
eval "$(npx -y ghqcd --init zsh)"The emitted function resolves its binary in three steps — ghqcd on PATH,
then the script that generated the snippet, then npx -y ghqcd@<version> — so
it keeps working after npm garbage-collects the npx cache. It is still worth a
global install: npx adds about a second to every jump.
Requires git, ghq and fzf on PATH (brew install git ghq fzf), and
Node >= 20.12. git is needed because ghq shells out to it.
Why --init exists
A child process cannot change its parent shell's working directory. npx ghqcd
therefore can only print where you wanted to go — which it does, in a
copyable box:
$ npx ghqcd api
╭─ next ────────────────────────────────────╮
│ │
│ cd "/Users/you/ghq/github.com/you/api" │
│ │
╰───────────────────────────────────────────╯
press c to copy · any other key to exit--init emits a shell function, and a function runs inside your shell, so it
can cd. This is the same mechanism zoxide
and starship use.
Usage
ghqcd [options] [<query>]| Option | Meaning |
| --- | --- |
| --init <shell> | print shell integration for zsh | bash | fish |
| --cmd <name> | function name emitted by --init (default: ghqcd) |
| --query <q> | initial fzf query (same as the positional) |
| --list | print every candidate instead of picking one |
| --json | stdout = 1-line JSON, never opens the fzf UI |
| --quiet | stdout = path only |
| --no-color | disable ANSI colors (also respects NO_COLOR) |
| -h, --help | show help |
| -V, --version | show version |
A query pre-filters fzf and auto-selects a unique match, so ghqcd api usually
lands without a keystroke.
For scripts and AI agents
--json never opens a UI, so it is safe in a pipeline or an agent session.
$ ghqcd --json api
{"schemaVersion":1,"path":"/Users/you/ghq/github.com/you/api","slug":"github.com/you/api","root":"/Users/you/ghq","matches":1}
$ ghqcd --list --json
{"schemaVersion":1,"count":3,"root":"/Users/you/ghq","repos":[{"path":"…","slug":"…"}]}matches tells you whether the query was unique — > 1 means the best-scoring
candidate was returned but the query was ambiguous.
Errors go to stderr as JSON, and stdout stays empty:
$ ghqcd --json durian
{"schemaVersion":1,"error":{"code":"E_NO_MATCH","message":"no repository matched 'durian'"},"exitCode":2}| Exit | Code | Meaning |
| --- | --- | --- |
| 0 | — | success |
| 1 | E_VALIDATION, E_GHQ, E_FZF | bad flags, or an upstream command failed |
| 2 | E_NO_MATCH | no repository matched |
| 3 | E_AMBIGUOUS | non-interactive with no query — pass one, or use --list |
| 127 | E_DEPS | ghq or fzf not installed |
| 130 | E_INTERRUPTED | Esc or Ctrl-C in fzf |
Cancelling the picker exits 130 silently — no error line lands above your next prompt.
Related
gwqcd— same idea for gwq worktreesgwqpull— clone with ghq, add a gwq worktree, and cd into itgwqadd— create a branch and its gwq worktree in the repo you are inghnew— create a GitHub repo, ghq-get it, and cd into it
License
MIT © ryoshin0830
