Repository management with ghq

I recently encountered ghq, a tool for automatically organising VCS-backed projects automatically. Give it a repository URL, it will clone a project to your projects dir (set by $GHQ_ROOT) like so:

$ ghq get https://github.com/motemen/ghq
# Runs `git clone https://github.com/motemen/ghq ~/.ghq/github.com/motemen/ghq`

I don’t like the idea of having projects hidden away, so I set $GHQ_ROOT to $HOME/projects.

From there, the list and look subcommands allow listing repositories and visiting them in the shell (actually a subshell).

I wanted a nicer way to visit project directories. Since I’m using fzf as a fuzzy-finder, I thought it would be nice to use it for this. I created a simple function, fp (find project) to do that:

fp () {
  ghq look $(ghq list | fzf +m)
}

I ran into some issues with the subshell of ghq look and wondered whether it might be possible to create a zsh command to remove the need for a subshell.

I found that fzf includes a cd-widget function and created something similar that uses ghq instead of find:

cd-project-widget () {
  local cmd="ghq list"
  setopt localoptions pipefail 2> /dev/null
  local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" fzf +m)"
  if [[ -z "$dir" ]]; then
    zle redisplay
    return 0
  fi
  cd $(ghq list --full-path | grep "$dir")
  local ret=$?
  zle reset-prompt
  typeset -f zle-line-init >/dev/null && zle zle-line-init
  return $ret
}
zle -N cd-project-widget

It should be quite simple to modify it to work with other fuzzy-finders. The basic idea is to show the output of ghq list for selection, and use ghq list --full-path with the selected candidate to print the correct directory for cd.

What’s really nice about this, is that I can bind it to a key sequence:

bindkey '\es' cd-project-widget

Now I can press M-s in a shell, start typing “nixfiles” and press enter to cd to my nixfiles project. Pretty neat!