- Go言語
go mod init・tidyの使い方|go.modとgo.sumとは
go mod init はモジュール(Goのコードをまとめる単位)を作って go.mod を生成するコマンド、go mod tidy はソースコードの import に合わせて go.mod と go.sum を過不足なく整えるコマンドです。 go.mod には「このモジュールの名前と、依存するモジュールの版」が、go.sum には「ダウンロードした内容が前回と同じかを確かめるためのハッシュ」が記録されます。
この記事では、init → get → tidy → 更新 → 削除(go get pkg@none)の流れを、各段階の go.mod / go.sum の中身つきで順に見ていきます。あわせて、コマンド早見表、go.mod のディレクティブ一覧、よく出るエラーの原文と対処もまとめました。出力はすべて Go 1.24.7(linux/amd64)で実行した結果です。
検証環境は外部ネットワークに出られないため、確認用に自作した3つのモジュール(example.com/greet、example.com/textutil、example.com/tools)をローカルのプロキシ(GOPROXY=file://...、GOSUMDB=off)に置いて実行しました。github.com/... などの公開モジュールでも、コマンドと go.mod の変化のしかたは同じです。出力中のパスは /home/taro/... に置き換えています(表示は環境に合わせて置き換えています)。
go modの早見表
コマンド早見表
| やりたいこと | コマンド | 変わるファイル |
|---|---|---|
| モジュールを作る | go mod init example.com/hello |
go.mod を作成 |
| import に合わせて整える | go mod tidy |
go.mod、go.sum |
| 整えたら何が変わるか見るだけ | go mod tidy -diff |
変更なし(差分を表示) |
| パッケージを追加する | go get example.com/greet |
go.mod、go.sum |
| 版を指定して追加・変更する | go get example.com/greet@v1.1.0 |
go.mod、go.sum |
| 最新にする | go get example.com/greet@latest |
go.mod、go.sum |
| 依存先も含めて更新する | go get -u example.com/greet |
go.mod、go.sum |
| パッケージを削除する | go get example.com/greet@none |
go.mod |
| ツールを追加する(Go 1.24〜) | go get -tool パッケージのパス |
go.mod に tool 行 |
| 依存を先にダウンロードする | go mod download |
go.sum(無ければ作成) |
| なぜ必要かを調べる | go mod why example.com/textutil |
変更なし |
| 依存関係のグラフを出す | go mod graph |
変更なし |
| 依存の一覧と更新の有無を見る | go list -m -u all |
変更なし |
| 公開されている版を一覧する | go list -m -versions example.com/greet |
変更なし |
| キャッシュの内容を検証する | go mod verify |
変更なし |
| 依存を vendor ディレクトリへコピーする | go mod vendor |
vendor/ を作成 |
| go.mod をコマンドで編集する | go mod edit -replace 旧=新 など |
go.mod |
| 複数モジュールをまとめて開発する | go work init ./a ./b |
go.work を作成 |
go.modとgo.sumの違い
| 比べる点 | go.mod | go.sum |
|---|---|---|
| 役割 | モジュール名と、依存するモジュールの版を宣言する | ダウンロードした内容のハッシュを記録する |
| 中身の例 | require example.com/greet v1.2.0 |
example.com/greet v1.2.0 h1:vx6q...= |
| 手で編集するか | することもある(go mod edit が安全) |
しない(コマンドに任せる) |
| Gitに入れるか | 入れる | 入れる |
| 無いとどうなるか | モジュールとして扱われない | missing go.sum entry で止まる |
手順1:go mod initでモジュールを作る
mkdir hello && cd hello
go mod init example.com/hello
cat go.mod
実行結果:
go: creating new go.mod: module example.com/hello
module example.com/hello
go 1.24.7
引数の example.com/hello がモジュールパス(モジュールの名前)です。 公開する予定があるなら github.com/ユーザー名/リポジトリ名 のように取得元と同じ形にします。手元だけで使うなら example.com/hello のような名前で構いません。go の行には、使っている Go の版が自動で入ります。
次に、外部のパッケージを import する main.go を用意します。
package main
import (
"fmt"
"example.com/greet"
)
func main() {
fmt.Println(greet.Hello("gopher"))
}
この時点で go run . を実行すると、依存がまだ登録されていないことを教えてくれます。
main.go:6:2: no required module provides package example.com/greet; to add it:
go get example.com/greet
手順2:go getでパッケージを追加する
go get example.com/greet@v1.0.0
go: downloading example.com/greet v1.0.0
go: added example.com/greet v1.0.0
go.mod(追加後):
module example.com/hello
go 1.24.7
require example.com/greet v1.0.0 // indirect
go.sum(新しく作られる):
example.com/greet v1.0.0 h1:OESONE+El+COGRCcyP3DBItsRznDe/wycz2LaNzQC9Y=
example.com/greet v1.0.0/go.mod h1:rcTgdhGf2dvXrNywJG0jkV+0342RC7PiKN0YX33Ej6Y=
go run .
Hello, gopher! (greet v1.0.0)
ここで気づく点が2つあります。
- main.go で直接 import しているのに
// indirectが付いています。go get単体では import の有無までは整理されません。この印は次のgo mod tidyで正しく付け直されます。 - go.sum は1つの版につき2行です。1行目がモジュール全体(zip)のハッシュ、
/go.modが付いた2行目が go.mod ファイルだけのハッシュです。
@v1.0.0 を省略して go get example.com/greet とすると、最新の版が選ばれます。
手順3:バージョンを指定して更新する
公開されている版は go list -m -versions で確認できます。
go list -m -versions example.com/greet
example.com/greet v1.0.0 v1.1.0 v1.2.0
v1.1.0 に上げてみます。v1.1.0 は内部で example.com/textutil を使っています。
go get example.com/greet@v1.1.0
go: downloading example.com/greet v1.1.0
go: downloading example.com/textutil v0.3.0
go: upgraded example.com/greet v1.0.0 => v1.1.0
go: added example.com/textutil v0.3.0
go.mod(差分):
-require example.com/greet v1.0.0 // indirect
+require (
+ example.com/greet v1.1.0 // indirect
+ example.com/textutil v0.3.0 // indirect
+)
go.sum には v1.1.0 と textutil v0.3.0 の行が追記され、v1.0.0 の行もそのまま残ります(この時点で6行)。
更新できる版があるかは go list -m -u all で一覧できます。
go list -m -u all
example.com/hello
example.com/greet v1.1.0 [v1.2.0]
example.com/textutil v0.3.0 [v0.4.0]
角かっこの中が、更新できる版です。 -u を付けた go get は、指定したモジュールに加えて、その依存先も新しい版に上げます。
go get -u example.com/greet
go: downloading example.com/greet v1.2.0
go: downloading example.com/textutil v0.4.0
go: upgraded example.com/greet v1.1.0 => v1.2.0
go: upgraded example.com/textutil v0.3.0 => v0.4.0
go run .
Hello, GOPHER! (greet v1.2.0 / textutil v0.4.0)
| 書き方 | 動き | 今回の結果 |
|---|---|---|
go get pkg@v1.1.0 |
その版にする(上げる・下げるどちらも可) | greet v1.0.0 → v1.1.0 |
go get pkg@latest |
そのモジュールだけ最新にする | greet → v1.2.0(textutil はそのまま) |
go get -u pkg |
そのモジュールと依存先を新しい版にする | greet → v1.2.0、textutil → v0.4.0 |
go get -u ./... |
自分のコードが使う依存をまとめて新しくする | (未実行) |
go get -u=patch pkg |
パッチ版の範囲だけ上げる | (未実行) |
版を下げることもできます。go get example.com/greet@v1.1.0 を実行すると、次のように表示されました。
go: downgraded example.com/greet v1.2.0 => v1.1.0
手順4:go mod tidyで整える
ここまでで go.mod は次の状態です(// indirect が実態と合っておらず、go.sum には使わなくなった版の行が残っています)。
require (
example.com/greet v1.2.0 // indirect
example.com/textutil v0.4.0 // indirect
)
go mod tidy
go.mod(tidy 後):
module example.com/hello
go 1.24.7
require example.com/greet v1.2.0
require example.com/textutil v0.4.0 // indirect
go.sum(tidy 後。10行から4行に):
example.com/greet v1.2.0 h1:vx6qzHG2xYogOpPCKdm01yk4afFGwDIO2TlnU7Nz4eg=
example.com/greet v1.2.0/go.mod h1:LNpKFOQstE7A4doP31zjjod9pCtsQi5CXgTnKQhatj0=
example.com/textutil v0.4.0 h1:4b1Jham+WkbbY4kSG3XVJQwBOFy/dIlL7/mmX1CSGV4=
example.com/textutil v0.4.0/go.mod h1:qypvavMD4Fr08zDyhe/hKxUFqGubmHfq1kovmYR5Xqw=
tidy がしてくれたことは3つです。
| tidy の働き | 今回の変化 |
|---|---|
直接 import しているものから // indirect を外す |
greet が1つ目の require ブロックへ |
| 間接的な依存を別ブロックに分ける | textutil が2つ目のブロックへ(// indirect 付き) |
| 使っていない版の行を go.sum から除く | v1.0.0・v1.1.0・textutil v0.3.0 の行が消えた |
// indirect は、「自分のコードは直接 import していないが、依存先が必要としているモジュール」という印です(意味は go.dev の Go Modules Reference で確認しました)。
tidyは「import を書いてから実行」でも使える
go get を使わず、ソースに import を書いてから go mod tidy を実行する流れでも依存を追加できます。require が無い状態から実行した結果です。
go: finding module for package example.com/greet
go: found example.com/greet in example.com/greet v1.2.0
require example.com/greet v1.2.0
require example.com/textutil v0.3.0 // indirect
直接 import した greet は最新の v1.2.0、間接的な textutil は greet が要求している v0.3.0 になりました(最新の v0.4.0 ではありません)。Go は「必要とされている版のうち最小限のもの」を選ぶ方式のため、間接的な依存は勝手に最新へは上がりません。上げたいときは go get -u か、版を指定した go get を使います。
変更前に差分だけ確認する(tidy -diff)
-diff を付けると、ファイルを書き換えずに差分を表示します。main.go から greet の import を消した状態で実行した結果です。
go mod tidy -diff
diff current/go.mod tidy/go.mod
--- current/go.mod
+++ tidy/go.mod
@@ -1,7 +1,3 @@
module example.com/hello
go 1.24.7
-
-require example.com/greet v1.2.0
-
-require example.com/textutil v0.4.0 // indirect
(続けて go.sum の差分も表示されます。)
手順5:パッケージを削除する(go get pkg@none)
依存を外す方法は2つあります。
| 方法 | 手順 | 向いている場面 |
|---|---|---|
A. import を消して go mod tidy |
ソースから import を削除 → tidy | 普段はこちら。go.sum まで一度に片付く |
B. go get pkg@none |
コマンドで require を外す | 特定のモジュールを明示的に外したいとき |
B を、import を消したあとに実行した結果です。
go get example.com/greet@none
go: removed example.com/greet v1.2.0
go.mod(実行後):
module example.com/hello
go 1.24.7
require example.com/textutil v0.4.0 // indirect
greet の行は消えましたが、間接的な依存だった textutil の行と go.sum の中身は残りました。 続けて go mod tidy を実行すると、go.mod は module と go の2行だけになり、go.sum はファイルごと無くなりました。
ソースにまだ import が残っている状態で @none を実行した場合は、require だけが消えるため、ビルドで次のように表示されます。
main.go:6:2: no required module provides package example.com/greet; to add it:
go get example.com/greet
「import を消す → go mod tidy」の順にすると、この行き違いが起きません。@none を使ったあとも、最後に tidy で仕上げるのがおすすめです。
go.modのディレクティブ一覧
| ディレクティブ | 書き方の例 | 意味 |
|---|---|---|
module |
module example.com/hello |
このモジュールのパス(名前)。import するときの先頭部分になる |
go |
go 1.24.7 |
このモジュールが必要とする Go の最小の版。使える言語機能にも影響する |
toolchain |
toolchain go1.24.7 |
使う Go ツールチェーンの提案(Go 1.21〜)。今回は未実行 |
require |
require example.com/greet v1.2.0 |
依存するモジュールと、その最小の版 |
// indirect |
require example.com/textutil v0.4.0 // indirect |
自分のコードからは直接 import していない依存に付くコメント |
replace |
replace example.com/greet => ../greet-local |
モジュールの中身を別の場所や版に差し替える(メインのモジュールでだけ有効) |
exclude |
exclude example.com/textutil v0.4.0 |
その版を読み込み対象から外す |
tool |
tool example.com/tools/cmd/hellotool |
go tool で実行できるツールとして登録する(Go 1.24〜) |
retract |
retract v1.0.1 |
モジュールの作者が、公開済みの版を取り下げる印(今回は未実行) |
godebug |
godebug default=go1.21 |
メインのモジュールに適用する GODEBUG 設定(Go 1.24〜の記載。今回は未実行) |
各ディレクティブの意味は、今回 go.dev の Go Modules Reference を開いて確認しました。
replaceで手元のコードに差し替える
依存先のモジュールを手元で直しながら試したいときに使います。../greet-local に同じモジュールパス(module example.com/greet)の go.mod と修正版のコードを置いた状態で実行しました。
go mod edit -replace example.com/greet=../greet-local
go run .
Hello, gopher! (手元で修正中のgreet)
go.mod には次の1行が加わります。
replace example.com/greet => ../greet-local
go list -m all でも差し替えが見えます。
example.com/hello
example.com/greet v1.2.0 => ../greet-local
元に戻すときは go mod edit -dropreplace example.com/greet のあと go mod tidy を実行します。replace は自分のモジュールをビルドするときだけ効き、他の人があなたのモジュールを依存として使うときには無視されるので、手元での確認が終わったら外しておくと混乱がありません。
toolディレクティブでツールの版をそろえる(Go 1.24〜)
コード生成やリンターなど、開発時に使うコマンドの版を go.mod で管理できます。
go get -tool example.com/tools/cmd/hellotool@v0.1.0
go: downloading example.com/tools v0.1.0
go: added example.com/tools v0.1.0
go.mod(実行後):
module example.com/hello
go 1.24.7
require example.com/greet v1.2.0
require (
example.com/textutil v0.3.0 // indirect
example.com/tools v0.1.0 // indirect
)
tool example.com/tools/cmd/hellotool
登録したツールは go tool 名前 で実行できます。
go tool hellotool a b
hellotool v0.1.0 args: [a b]
引数なしの go tool を実行すると、標準のツール(vet など)の一覧の末尾に example.com/tools/cmd/hellotool が並びました。tool 行がある間は、go mod tidy を実行しても tools の require は消えません。 外すときは go get -tool example.com/tools/cmd/hellotool@none で tool 行を消し、続けて go mod tidy を実行します。
依存を調べるコマンド(why・graph・verify・download)
go mod why example.com/textutil
# example.com/textutil
example.com/hello
example.com/greet
example.com/textutil
上から順に「hello が greet を import し、greet が textutil を import している」と読みます。身に覚えのない依存が go.mod にあるとき、どこから来たのかがわかります。
go mod graph
example.com/hello example.com/greet@v1.2.0
example.com/hello example.com/textutil@v0.4.0
example.com/hello go@1.24.7
example.com/greet@v1.2.0 example.com/textutil@v0.3.0
example.com/greet@v1.2.0 go@1.21
example.com/textutil@v0.4.0 go@1.21
go@1.24.7 toolchain@go1.24.7
1行が「左が右を要求している」という関係です。greet 自身は textutil v0.3.0 を要求していますが、hello が v0.4.0 を要求しているため、ビルドには v0.4.0 が使われます。
go mod verify
all modules verified
go mod download は、ビルドの前に依存をまとめて取得しておくコマンドです。CI や Docker のビルドで、ソースをコピーする前に go.mod と go.sum だけで実行しておくと、キャッシュが効きやすくなります(Docker でのビルドは今回未実行です)。
vendor・go mod edit・go workの使いどころ
go mod vendor:依存をリポジトリの中に置く
go mod vendor
find vendor -type f
vendor/example.com/greet/greet.go
vendor/example.com/textutil/textutil.go
vendor/modules.txt
vendor/modules.txt には、コピーしたモジュールと版が記録されます。
# example.com/greet v1.2.0
## explicit; go 1.21
example.com/greet
# example.com/textutil v0.3.0
## explicit; go 1.21
example.com/textutil
vendor ディレクトリがある状態で go build ./... が通ることを確認しました。ネットワークに出られない環境でビルドしたいときに便利です。
go mod edit:スクリプトからgo.modを書き換える
| コマンド | 働き |
|---|---|
go mod edit -go=1.23 |
go 行を書き換える |
go mod edit -require=example.com/textutil@v0.3.0 |
require を追加する |
go mod edit -droprequire=example.com/textutil |
require を削除する |
go mod edit -replace 旧=新 / -dropreplace 旧 |
replace を追加・削除する |
go mod edit -exclude=example.com/textutil@v0.4.0 |
exclude を追加する |
go mod edit -print |
現在の go.mod を表示する |
go mod edit -json |
JSON 形式で表示する |
表のコマンドはすべて実行して、go.mod が期待どおり変わることを確認しました。edit は go.mod の文字を書き換えるだけで、ダウンロードや整合性の確認はしません。 実行後は go mod tidy で整えます。
go work:複数のモジュールを同時に開発する
replace を go.mod に書かずに、手元の複数モジュールをまとめて扱う仕組みです。
go work init ./hello ./greet-local
cat go.work
go 1.24.7
use (
./greet-local
./hello
)
この状態で hello の中から go run . を実行すると、go.mod には replace が無いのに手元の greet が使われました。
Hello, gopher! (手元で修正中のgreet)
GOWORK=off go run . とすると、go.work を無視して通常どおり v1.2.0 が使われます。
| 比べる点 | replace | go work |
|---|---|---|
| 書く場所 | go.mod | go.work(モジュールの外) |
| 向いている場面 | 一時的に1つ差し替える | 複数モジュールを継続して同時に開発する |
| 共有するか | go.mod に残るので注意が必要 | go.work は手元専用にすることが多い |
よく出るエラーと対処
実際に再現したメッセージの原文です(Go 1.24.7)。
no required module provides package
main.go:6:2: no required module provides package example.com/greet; to add it:
go get example.com/greet
原因:import しているパッケージが go.mod の require に無い。
対処:表示されている go get ... を実行するか、go mod tidy を実行します。
missing go.sum entry
go.sum を削除した状態で go build ./... を実行すると表示されました。
main.go:6:2: missing go.sum entry for module providing package example.com/greet (imported by example.com/hello); to add:
go get example.com/hello
原因:go.mod には require があるのに、対応する行が go.sum に無い(go.sum をコミットし忘れた、手で消した、など)。
対処:go mod tidy を実行します。今回は go mod download でも go.sum が作り直され、ビルドが通りました。
module declares its path as ... but was required as ...
go: example.com/oldname@v1.0.0 requires example.com/oldname@v1.0.0: parsing go.mod:
module declares its path as: example.com/newname
but was required as: example.com/oldname
原因:取得しようとしたパスと、そのモジュールの go.mod の module 行に書かれた名前が違う。リポジトリの移転や改名のあと、fork したリポジトリを直接指定したときによく見られます。
対処:declares its path as に表示された名前(ここでは example.com/newname)で import と go get をやり直します。fork を使いたい場合は、元の名前のまま require し、replace で fork に差し替えます。
updates to go.mod needed
go.mod から必要な require を1行消した状態でビルドすると表示されました。
go: updates to go.mod needed; to update it:
go mod tidy
対処:メッセージのとおり go mod tidy を実行します。
checksum mismatch(SECURITY ERROR)
go.sum のハッシュを1文字書き換えてビルドすると表示されました。
verifying example.com/greet@v1.2.0: checksum mismatch
downloaded: h1:vx6qzHG2xYogOpPCKdm01yk4afFGwDIO2TlnU7Nz4eg=
go.sum: h1:Xx6qzHG2xYogOpPCKdm01yk4afFGwDIO2TlnU7Nz4eg=
SECURITY ERROR
This download does NOT match an earlier download recorded in go.sum.
原因:ダウンロードした内容と go.sum の記録が一致しない。
対処:まず go.sum を手で編集していないか、マージで行が崩れていないかを確認します。go.sum をバージョン管理の状態に戻すとビルドが通りました。同じ版の中身が後から差し替えられた場合にもこの表示になるため、心当たりが無いときは取得元を確かめます。
go.mod file not found
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
対処:モジュールのディレクトリへ移動するか、go mod init モジュールパス を実行します。
go mod init まわりの2つ
引数なしで実行したとき:
go: cannot determine module path for source directory /home/taro/empty (outside GOPATH, module path must be specified)
Example usage:
'go mod init example.com/m' to initialize a v0 or v1 module
'go mod init example.com/m/v2' to initialize a v2 module
すでに go.mod があるとき:
go: /home/taro/empty/go.mod already exists
エラーの逆引き表
| メッセージの要点 | 原因 | まず試すこと |
|---|---|---|
no required module provides package |
require に無い | go get パッケージ または go mod tidy |
missing go.sum entry |
go.sum に行が無い | go mod tidy |
module declares its path as |
パスと module 行の名前が違う | 表示された名前で取得する/replace を使う |
updates to go.mod needed |
go.mod の内容が足りない | go mod tidy |
checksum mismatch |
go.sum と内容が一致しない | go.sum を元の状態に戻して原因を確認 |
go.mod file not found |
モジュールの外で実行した | ディレクトリを確認/go mod init |
cannot determine module path |
init に引数が無い | go mod init example.com/名前 |
go.mod already exists |
すでに初期化済み | そのまま使う |
よくある質問
Q. go.sum はGitにコミットしますか?
A. コミットします。go.mod と go.sum の両方がそろっていると、ほかの人やCIでも同じ内容の依存でビルドできます。go.sum が無い状態では missing go.sum entry と表示されることを確認しました。
Q. go get と go mod tidy はどう使い分けますか?
A. 版を指定して追加・更新・削除したいときは go get、import の状態に合わせて全体を整えたいときは go mod tidy です。go get だけでは // indirect の付き方や go.sum の不要な行が残るため、最後に tidy を実行しておくと整います。
Q. go.mod に書かれた // indirect は消してよいですか?
A. 手で消す必要はありません。直接 import していない依存に自動で付く印で、go mod tidy が実態に合わせて付けたり外したりします。
Q. go install と go get の違いは何ですか?
A. go get は go.mod の依存を変更するコマンド、go install パッケージ@版 はコマンドをビルドしてインストールするコマンドです(go install は今回未実行)。モジュールごとにツールの版をそろえたい場合は、Go 1.24以降の go get -tool と go tool が使えます。
まとめ
go mod init モジュールパスで go.mod を作る。中身は module 行と go 行だけから始まります。- 追加は
go get pkg、版の指定は@v1.2.3、最新は@latest、依存先ごと更新は-u。 - 削除は「import を消して
go mod tidy」が基本。go get pkg@noneは require を明示的に外したいときに使い、最後に tidy で仕上げます。 go mod tidyは// indirectの整理と go.sum の掃除まで行う。変更前に-diffで確認できます。- go.mod は「何をどの版で使うか」、go.sum は「中身が同じかの確認用」。どちらもコミットします。
- 手元の差し替えは replace、複数モジュールの同時開発は go work、ツールの版管理は tool ディレクティブ。
- エラーの多くは
go mod tidyで解消。module declares its path asは名前を、checksum mismatchは go.sum を確認します。
参考・出典
- Go Modules Reference(go.dev/ref/mod)― ディレクティブの意味、
// indirect、go.sum の形式、go get pkg@none、go mod tidyのフラグを確認 - 本文の実行結果は Go 1.24.7(linux/amd64)で、自作の確認用モジュールをローカルプロキシ(
GOPROXY=file://...、GOSUMDB=off)に置いて実行したものです。公開モジュールの取得、toolchain・retract・godebug ディレクティブ、go get -u ./...、go get -u=patch、go installは未実行です。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。