summary refs log tree commit diff stats
path: root/content/post/repository-management-with-ghq.md
blob: 6006605351455b83f0b25c4a8fed56f0fb259c27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
+++
Tags = ["development","git"]
date = "2017-05-06T23:31:51+02:00"
title = "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:

{{< highlight sh >}}
$ ghq get https://github.com/motemen/ghq
# Runs `git clone https://github.com/motemen/ghq ~/.ghq/github.com/motemen/ghq`
{{< /highlight >}}

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:

{{< highlight sh >}}
fp () {
  ghq look $(ghq list | fzf +m)
}
{{< /highlight >}}

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][fzf-cd-widget] and created
something similar that uses `ghq` instead of `find`:

{{< highlight sh >}}
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
{{< /highlight >}}

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:

{{< highlight sh >}}
bindkey '\es' cd-project-widget
{{< /highlight >}}

Now I can press `M-s` in a shell, start typing "dotfiles" and press enter to `cd`
to my [dotfiles][] project. Pretty neat!

[ghq]:https://github.com/motemen/ghq
[fzf]:https://github.com/junegunn/fzf
[fzf-cd-widget]:https://github.com/junegunn/fzf/blob/337cdbb37c1efc49b09b4cacc6e9ee1369c7d76d/shell/key-bindings.zsh#L40-L54
[dotfiles]:https://git.alanpearce.eu/dotfiles