😺

go.modでコミット単位のバージョン指定

に公開

はじめに

go.modを使っている際に、特定のタグバージョンだけでなく、特定のコミットやブランチを指定してモジュールを使用したいケースがあります。この記事では、go.modで特定のコミットやブランチを指定する方法について、疑似バージョン(Pseudo-version)の仕組みと共に解説します。

疑似バージョンとは

Go moduleでは、セマンティックバージョニング(SemVer)を採用していますが、タグが付いていないコミットを参照するために「疑似バージョン」(Pseudo-version)という仕組みがあります。

疑似バージョンは次の形式で表されます:

vX.0.0-yyyymmddhhmmss-abcdefabcdef

または

vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef

の形式は以下の情報を含んでいます。

  • ベースバージョン(vX.0.0 や vX.Y.(Z+1)-0)
    • vX.0.0 はリポジトリに既知のベースバージョンがない場合に使用
    • vX.Y.(Z+1)-0 はベースバージョンが vX.Y.Z のようなリリースバージョンの場合に使用
      • 例:ベースバージョンが v1.2.3 の場合、疑似バージョンは v1.2.4-0.yyyymmddhhmmss-abcdefabcdef になる
  • コミット日時(UTC):yyyymmddhhmmss 形式で表されたコミットのタイムスタンプ
  • コミットハッシュの先頭12文字:特定のコミットを一意に識別するための情報

疑似バージョンには以下のような特性があります。

  • 同じベースバージョンを持つ疑似バージョンは時系列でソートされる
  • 疑似バージョンは常にそのベースバージョンよりも高く、次のリリースバージョンよりも低い順序で比較される
  • Go ツールチェーンは、疑似バージョンのタイムスタンプとコミットハッシュが実際のリポジトリの情報と一致することを検証する

これにより、Go moduleは未リリースのコードに対しても厳密なバージョン管理を可能にしています。

コミット単位で依存関係を指定する方法

1. 直接 go get でコミットハッシュやブランチ名を指定

実際に go get コマンドでコミットハッシュやブランチ名を指定して依存関係を追加できます。

# コミットハッシュを指定(例: gorilla/mux のコミット)
go get github.com/gorilla/mux@db9d1d0

# ブランチ名を指定(例: main ブランチ)
go get github.com/gorilla/mux@main

これを実行すると、Go ツールチェーンは自動的に疑似バージョンを生成し、go.mod ファイルに追加します。

例えば、上記のようにコミットハッシュを指定した場合、go.mod には次のような疑似バージョンが記録されます:

require (
	require github.com/gorilla/mux v1.8.2-0.20240619235004-db9d1d0073d2 // indirect
)

2. go list で疑似バージョンを確認

特定のコミットやブランチに対応する疑似バージョンや詳細情報を知りたい場合は、以下のようなコマンドを使うことができます。

go list -m -json github.com/gorilla/mux@db9d1d0
go list -m -json github.com/gorilla/mux@main

このコマンドは以下のような JSON 出力を返します(例:mainブランチ指定時):

{
  "Path": "github.com/gorilla/mux",
  "Version": "v1.8.2-0.20240619235004-db9d1d0073d2",
  "Query": "main",
  "Time": "2024-06-19T23:50:04Z",
  "Dir": "/Users/youruser/go/pkg/mod/github.com/gorilla/mux@v1.8.2-0.20240619235004-db9d1d0073d2",
  "GoMod": "/Users/youruser/go/pkg/mod/cache/download/github.com/gorilla/mux/@v/v1.8.2-0.20240619235004-db9d1d0073d2.mod",
  "GoVersion": "1.24",
  "Sum": "h1:oZRjfKe/6Qh676XFYvylkCWd0gu8KVZeZYZwkNw6NAU=",
  "GoModSum": "h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=",
  "Origin": {
    "VCS": "git",
    "URL": "https://github.com/gorilla/mux",
    "Hash": "db9d1d0073d27a0a2d9a8c1bc52aa0af4374d265"
  }
}

この例では、Version フィールドに疑似バージョンが記録されています。

擬似バージョンを指定する場合

以下のようなケースで擬似バージョンを指定する場合があるかなと思います。

  • OSSでバグ等を見つけ、修正のプルリクエストを送信したものの、マージされるまで待てない場合。
  • チームの別のメンバーが開発中の機能を試したい場合。
  • まだ正式なリリースがないプロジェクトや、タグ付けの慣行がないプロジェクトを試したい場合。

まとめ

Go moduleは疑似バージョンを通じて、タグ付けされていないコミットに対しても安定した参照を提供しています。これにより、開発中の機能のテストやバグ修正の検証、正式なリリースがないプロジェクトを利用することなどが可能になっています。

参考

Discussion