はじめに (対象読者・この記事でわかること)

この記事は、Go 言語で開発を行っているエンジニアや、これから Go のパッケージ管理を学びたい初心者を対象としています。
特に go get コマンドを実行したときに出てくる ...(トリプルドット)が何を意味するのかが分からない、という疑問を抱えている方に向けて執筆しました。

この記事を読むことで、以下が分かります。

  • ... が示す「パッケージのバージョン指定やインポートパスの省略」についての正確な意味
  • Go モジュールの取得フローと、go get が内部で行っている処理の全体像
  • トリプルドットが含まれる URL を実際に使う際のベストプラクティスと注意点

Go の依存管理を正しく理解し、効率的にコードベースを拡張できるようになることが目的です。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • Go の基本的な文法と、go.mod ファイルの役割
  • 基本的なターミナル操作(cdlsgo version など)

go get の URL に現れる「...」とは?(概要・背景)

Go のパッケージ取得に用いられる go get コマンドは、リモートリポジトリからソースコードをダウンロードし、ローカルのモジュールキャッシュに格納します。その際、取得対象を示す URL の末尾に トリプルドット(... が付くことがあります。

トリプルドットの主な意味

  1. 再帰的インポート
    example.com/project/... と書くと、example.com/project 以下のすべてのサブパッケージ(example.com/project/sub1example.com/project/sub2/... など)を対象に取得します。これは「このディレクトリ配下の全てを取得したい」ことを簡潔に表現するための記法です。

  2. バージョンの省略
    Go modules が導入された後、go get example.com/project@v1.2.3 のように @ でバージョンを指定できますが、... が付くと最新の安定版(あるいは go.modgo バージョンに合わせたデフォルトの解決策)を暗黙的に取得します。実際には、... は「パッケージの最新版を再帰的に取得」するという意味合いで用いられます。

  3. パターンマッチング
    ... は 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 を実行

Bash
go 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:対象バージョンを確認

Bash
go list -m -versions github.com/example/awesome-project # => v1.0.0 v1.2.1 v2.0.0

ステップ 2:バージョン付きで ... を使用

Bash
go get github.com/example/awesome-project@v1.2.1...
  • @v1.2.1... は「v1.2.1 以降のすべてのサブパッケージ」を取得するという意味です。実際には v1.2.1go.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.modreplace ./... => ./local/... のようにワイルドカードを利用できないため、個別に replace を列記するか、replace なしで取得後に手動でパスを書き換える。

実践的なベストプラクティス

  1. 必ずバージョンを明示:CI 環境やビルドの再現性を担保するため、... を使う場合でも @vX.Y.Z を付与する。
  2. モジュールキャッシュのクリア:古いキャッシュが残っていると意図しないバージョンが取得されることがあります。
    bash go clean -modcache
  3. go mod tidy の活用:取得後に不要な依存を削除し、go.modgo.sum を整合させる。
    bash go mod tidy

まとめ

本記事では、go get の URL に出てくるトリプルドット(... が持つ 3 つの主要な意味—再帰的インポート、バージョン省略、パターンマッチング—を解説し、実際の取得シナリオを通じて具体的な手順とトラブルシューティングを提示しました。

  • 要点 1... は「ディレクトリ配下の全サブパッケージ」を一括で取得する記法であり、モジュール版と GOPATH 版で振る舞いが異なる。
  • 要点 2:バージョンを明示しつつ ... を使用すると、特定リリース以降の全サブパッケージを安全に取得できる。
  • 要点 3:取得エラーは多くの場合、プロキシ設定・モジュール非対応・バージョン指定ミスが原因。go envgo list -m -versionsgo clean -modcache で対処可能。

この記事を読むことで、Go の依存管理を正確にコントロールできるようになり、プロジェクトのビルド・デプロイがより安定 します。次回は「go mod edit で高度な replace パターンを管理する方法」や、go work を使ったマルチモジュールワークスペースの構築 について取り上げる予定です。

参考資料