はじめに
普段自分はmotemenさんのghqを使ってリポジトリを管理しています.
これを用いた場合,通常は~/.ghq以下の適当な位置にリポジトリが配置されます.
ところで最近,go言語に手を出したのですが,はじめに$GOPATHを~/.goと設定して作業し始めました.
しかしこの場合,ghq getしたリポジトリが$GOPATH/src以下に配置されないことから,importやdepを使う際にエラーが生じました.
そのとき,この問題について検索すると様々な解決方法がヒットし,どの方法が最適解なのかわからずややハマってしまいました.
そこで今回はgo言語のリポジトリを扱う上でどの方法が良いのかまとめてみようと思います.
ghqを活用する上でgo言語のリポジトリをどのように扱うか
方法1 $GOPATHを複数設定する
まずは$GOPATHが設定されていないことが問題なのでそれを設定することを考えます.
以下のようにして$GOPATHは複数設定することができます
# 例: ~/.bashrcに以下を記述
export GOPATH=$HOME/.go:$HOME/.ghq
このように$GOPATHを複数指定した場合は,go getした際はプライマリのパスが採用され,importやdepの際はセカンダリ以降のパスも見る仕様のようです.
あとは.ghq/github.com/...となっている構造を.ghq/src/github.com/...とすることで冒頭の問題は解決できます.
問題点
.ghq以下が汚くなる
.ghq/src/github.com/...にリポジトリを移動させないといけないため.ghq/直下にsrc/というディレクトリが作られ,決してきれいな構造であるとは言えません(きれいな構造とは).
またdep ensureを走らせると.ghq/pkg/も生成され,他の言語のリポジトリも管理している場合とても面倒です.ghq getしたあとにその都度.ghq/src/に移動させるのも大変です.
方法2 $GOPATH/src/以下もghq rootに含める
この方法ではgo言語のリポジトリは全てgo getで取得し$GOPATH/src以下で管理します.($GOPATHは増やさない)
ただしこのままだとpecoなどを使っている人はghq listとしても対象のリポジトリが引っかからないため不都合が生じます.このため次の通りにします.
ghq listはghq root以下のリポジトリを表示してくれますが,このghq rootは.gitconfigの記述に基づいて設定されています(何も記述しないと~/.ghqに設定される).またこれは複数設定できるため以下のようにして$GOPATH/srcもrootに設定します.
# プライマリパスに`ghq get`でもってきたいディレクトリのパスを設定
git config --global --add ghq.root $HOME/.ghq
# $GOPATH以下も管理対象にする
git config --global --add ghq.root $GOPATH/src
# 確認
git config --global --get-all ghq.root
.gitconfigはこのようになります
(省略)
[ghq]
root = /home/{{your_name}}/.ghq
root = /home/{{your_name}}/go/src
問題点
"go get" と "ghq get" を使い分ける必要がある
go言語のリポジトリはgo getでそれ以外のリポジトリはghq getを使う必要があります.誤ってgo getとするところをghq getとしてもcpを使えば大丈夫ですが,慣れるまでは使い分けが面倒に感じられるかもしれません.
リポジトリの位置が統一されない
go言語を用いたものは.go/以下にそれ以外は.ghq/以下になるため同一ディレクトリで管理したくてもそれができなくなります.しかしこの問題は普段,pecoを使ってディレクトリ移動をしている人には大した問題にはならないかと思われます.
方法3 ghq root を .go/src に設定する
この方法ではghq rootを.go/src以下に設定することで解決を図ります.方法は2番目のとき同様に.gitconfigにrootの場所を.go/srcとして記述します.これによりgo get,ghq getどちらにしても同一の場所にリポジトリがクローンされます.
問題点
.goの中身は決してgoだけではない...という状況になる
go get,ghq getどちらも.goディレクトリ以下に配置されるためにgo以外の言語で書かれたものも全て,go/内にあるという状況が生まれます.解決方法として.goではなく.repoなど(いい名前が思いつきませんでした...)に名前を変更してそれに応じてパスを書き換える手法が考えられますが,.repo/bin/はgoのソースから生成されたバイナリしか配置されないことなどに違和感を感じる人もいるかもしれません(自分は違和感を感じた).
結局,自分はどうしたのか
自分は方法2を採用することにしました."go言語はプログラムの管理方法を含めてgoである"と(勝手に)捉えた上でgoは.go/,それ以外は.ghq/以下に配置して作業しています.
ところでgo 1.11で試験導入,1.12からは正式採用予定のvgo(go.mod)では$GOPATHは不要になるようです.
将来的にはこのような問題も解消されるかもしれませんね.