はじめに (対象読者・この記事でわかること)
この記事は、Go 言語で開発を行っているエンジニアや、これから Go のパッケージ管理を学びたい初心者を対象としています。
特に go get コマンドを実行したときに出てくる ...(トリプルドット)が何を意味するのかが分からない、という疑問を抱えている方に向けて執筆しました。
この記事を読むことで、以下が分かります。
...が示す「パッケージのバージョン指定やインポートパスの省略」についての正確な意味- Go モジュールの取得フローと、
go getが内部で行っている処理の全体像 - トリプルドットが含まれる URL を実際に使う際のベストプラクティスと注意点
Go の依存管理を正しく理解し、効率的にコードベースを拡張できるようになることが目的です。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Go の基本的な文法と、
go.modファイルの役割 - 基本的なターミナル操作(
cd、ls、go versionなど)
go get の URL に現れる「...」とは?(概要・背景)
Go のパッケージ取得に用いられる go get コマンドは、リモートリポジトリからソースコードをダウンロードし、ローカルのモジュールキャッシュに格納します。その際、取得対象を示す URL の末尾に トリプルドット(...) が付くことがあります。
トリプルドットの主な意味
-
再帰的インポート
example.com/project/...と書くと、example.com/project以下のすべてのサブパッケージ(example.com/project/sub1、example.com/project/sub2/...など)を対象に取得します。これは「このディレクトリ配下の全てを取得したい」ことを簡潔に表現するための記法です。 -
バージョンの省略
Go modules が導入された後、go get example.com/project@v1.2.3のように@でバージョンを指定できますが、...が付くと最新の安定版(あるいはgo.modのgoバージョンに合わせたデフォルトの解決策)を暗黙的に取得します。実際には、...は「パッケージの最新版を再帰的に取得」するという意味合いで用いられます。 -
パターンマッチング
...は Go のfilepath.Matchのようなパターンマッチングで使われ、*と似たワイルドカードですが、スラッシュ/を跨いでマッチ可能です。これにより、階層構造を持つパッケージツリー全体を簡潔に指定できます。
歴史的背景
Go 1.11 以前は GOPATH が中心で、... は主に ビルドツール(go build ./... など)での再帰ビルドに使われていました。モジュールが正式に導入された Go 1.13 以降は、同様の記法が go get にも適用され、依存解決の幅が広がりました。これにより、特定のサブディレクトリだけを個別に取得するケースと、プロジェクト全体を一括で取得するケースを明確に分けて記述できるようになりました。
go get でトリプルドットを使う実践的な手順
以下では、実際に go get コマンドで ... を使用するシナリオを 2 つ紹介し、コマンド例・取得結果・トラブルシューティングまでを網羅的に解説します。
シナリオ 1:リポジトリ全体を取得してローカルにコピー
ステップ 1:プロジェクトのベースディレクトリを決める
Bash# 任意の作業ディレクトリに移動 mkdir -p ~/go-workspace/src && cd ~/go-workspace/src
ステップ 2:go get でトリプルドット付き URL を実行
Bashgo get github.com/example/awesome-project/...
- これにより、
github.com/example/awesome-project配下の すべてのモジュール が取得されます。 - 取得先は
$GOPATH/pkg/mod(モジュールキャッシュ)に格納され、go.modが自動生成されます。
ハマった点やエラー解決
| 発生したエラー | 原因 | 解決策 |
|---|---|---|
cannot find module providing package github.com/example/awesome-project/... |
... の後にサブパッケージが存在しないか、リポジトリが Go modules に対応していない |
リポジトリが go.mod を持っているか確認し、go get github.com/example/awesome-project(サブパッケージ指定なし)で取得してから手動でサブディレクトリを追加 |
go: downloading ... が永久に止まる |
ネットワークプロキシや社内ミラーの設定ミス | GOPROXY 環境変数を正しく設定(例: export GOPROXY=https://proxy.golang.org,direct) |
解決策の詳細
- モジュール未対応リポジトリ:
go getはモジュールが無い場合でもGOPATHモードで動作しますが、...はモジュールモード専用です。そのため、まずはgo get github.com/example/awesome-projectでベースパッケージを取得し、手動でcd $GOPATH/src/github.com/example/awesome-projectに移動してgo build ./...等を実行します。 - プロキシエラー:
go env -w GOPROXY=directにすると直接取得に切り替わりますが、社内の制限がある場合は社内ミラーの URL を設定してください。
シナリオ 2:特定のバージョンを指定しつつ全サブパッケージを取得
ステップ 1:対象バージョンを確認
Bashgo list -m -versions github.com/example/awesome-project # => v1.0.0 v1.2.1 v2.0.0
ステップ 2:バージョン付きで ... を使用
Bashgo get github.com/example/awesome-project@v1.2.1...
@v1.2.1...は「v1.2.1 以降のすべてのサブパッケージ」を取得するという意味です。実際にはv1.2.1のgo.modが参照され、その中に列挙されたモジュールに対して再帰的に取得が行われます。
ハマった点やエラー解決
-
バージョンが存在しない:
go get github.com/example/awesome-project@v9.9.9...とするとinvalid version: unknown revision v9.9.9が出ます。
対策:go list -m -versionsで使用可能なバージョンを事前に確認し、正しいものを指定する。 -
replace指示が失効:go.mod内でreplaceが記載されている場合、...が含むサブパッケージがreplaceの対象外になることがあります。
対策:go.modにreplace ./... => ./local/...のようにワイルドカードを利用できないため、個別にreplaceを列記するか、replaceなしで取得後に手動でパスを書き換える。
実践的なベストプラクティス
- 必ずバージョンを明示:CI 環境やビルドの再現性を担保するため、
...を使う場合でも@vX.Y.Zを付与する。 - モジュールキャッシュのクリア:古いキャッシュが残っていると意図しないバージョンが取得されることがあります。
bash go clean -modcache go mod tidyの活用:取得後に不要な依存を削除し、go.modとgo.sumを整合させる。
bash go mod tidy
まとめ
本記事では、go get の URL に出てくるトリプルドット(...) が持つ 3 つの主要な意味—再帰的インポート、バージョン省略、パターンマッチング—を解説し、実際の取得シナリオを通じて具体的な手順とトラブルシューティングを提示しました。
- 要点 1:
...は「ディレクトリ配下の全サブパッケージ」を一括で取得する記法であり、モジュール版と GOPATH 版で振る舞いが異なる。 - 要点 2:バージョンを明示しつつ
...を使用すると、特定リリース以降の全サブパッケージを安全に取得できる。 - 要点 3:取得エラーは多くの場合、プロキシ設定・モジュール非対応・バージョン指定ミスが原因。
go env・go list -m -versions・go clean -modcacheで対処可能。
この記事を読むことで、Go の依存管理を正確にコントロールできるようになり、プロジェクトのビルド・デプロイがより安定 します。次回は「go mod edit で高度な replace パターンを管理する方法」や、go work を使ったマルチモジュールワークスペースの構築 について取り上げる予定です。
参考資料
- Go Modules Reference (公式ドキュメント)
- go get コマンドの使い方 – Go Blog
- go.mod ファイルの書き方 – Go Documentation
- Go 言語でのパッケージパターンマッチング
