TL;DR
fork したリポジトリは clone せず、本家を go get すべし
経緯
Docker のコンテナ管理ツールを夢想してみたものの、なかなか険しい道のりなので、crane を拡張していく方向に切り替えました。で、最初にはまったポイントをメモ。いろいろなところで言及されているので今更感ありますが、ご了承ください。
お勧めの手順
普通は fork したものを clone して、本家へのリモート参照を upstream として追加しますが、Go の場合には逆になります。本家を get して、fork へのリモート参照を追加するのです。
- 本家のリポジトリを github で fork
- 環境変数
GOPATH
を適切に設定(迷ったらHOME
で良いでしょう) - 本家のリポジトリを
go get github.com/<userid>/<repo>
で複製する - 複製したディレクトリに
cd $GOPATH/src/github.com/<userid>/<repo>
で移動する - fork したリポジトリへのリモート参照を
git remote add fork https://github.com/<my-id>/<repo>
で追加する - トピックブランチ切って作業を行う
ブランチ切ってからの作業はいつもの手順とほぼ同じです。push 先が origin ではなく、fork であるとか、デフォルトの master ブランチが本家を指している、といったところに気をつければ、特に難しいところはありません。
なぜ fork したリポジトリを clone してはいけないのか?
Go には元からパッケージ管理機能が備わっており、GOPATH
環境変数を起点としてパッケージの存在確認を行います。パッケージのパスはローカルでも github のようなリモートでも良く、なければ GOPATH
以下に自動的にインストールしてくれます。
そして大抵の main.go には、本家のリポジトリを参照する import があります。
package main
import (
"github.com/michaelsauter/crane/crane"
)
func main() {
crane.RealMain()
}
当然ながら fork したリポジトリは github.com/<userid>
部分が自分のものに置き換わりますから、ビルドでコケます。なので、まずは本家を go get
するのがお作法になるわけです。
振り返り
最初は、fork したリポジトリに合わせて import を修正しようか...... なんて考えもチラリと浮かんだのですが、そんな乱暴な PR など通るはずもないしなぁと思い、お作法に辿り着きました。
Go のパッケージ管理は良くできているようで、案外、そうでもない気がしています。固有のリポジトリと強固な依存関係をソースコードに持ち込んでしまうのは、果たして良かったのか。リポジトリの物理的な場所は外出しにして、マッピングできるようになっているとか、DI 的なものでも良いのですが、そういった仕組みが用意してあれば今回のケースにもうまく対処できたように思います。
まあでも、git が柔軟だからどうとでもなるのですけどね。
教訓
Go に入っては Go に従え