🐈
go.modは構造宣言、tidyは再整合、replaceは応急処置
本記事の要点
- go.mod=構造宣言、tidy=再整合
- replace=応急処置、恒久禁止
go.modの正体
go.mod ファイルは依存関係を記述するファイルと思われがちですが、実は構造を宣言するファイルです。
誤解パターン
正解パターン
go mod tidyによる再整合
go mod tidy は、このメインモジュール配下の 全パッケージ(テスト・ツール含む)を読み込み、依存を再整合します。
不要な依存は削除され、go.sum ファイルも更新されます。
ただし、この時に 下層フォルダに別の go.mod(別モジュール) が混ざっていると、go.mod ファイルの不整合を引き起こすことがあります。
再整合時の不整合対策
go mod tidy の前に、構造のねじれを解消します。前提は 単一モジュール(下層に go.mod を置かない)です。
症状(よくあるパターン)
-
tidy後に 意図しない追加/削除 が大量発生する -
go.sumが毎回大きく変わる - 下層フォルダにも 別の
go.modがある
手順(3ステップ)
-
混在検知
-
find . -name go.mod -not -path "./go.mod"で下層のgo.modを洗い出します。 - 見つかったら 退避(リネーム or 別リポへ移動)。必要なら後日
go workへ昇格します。
-
-
前提を揃える
-
rm -rf vendor/(使っていれば後で再生成) -
git restore --staged go.mod go.sum(一度きれいに) - キャッシュ由来なら
go clean -modcache
-
-
再整合→差分確認
-
go mod tidyを実行 -
git diff go.mod go.sumで 追加/削除のみ を確認 - 使っていない
requireを外し、replaceは 応急処置のみ(コミットしない)
-
検証(軽量)
-
go build ./...とgo list -m allで整合を確認します。 -
vendorを使う場合はgo mod vendorで再生成します。
replaceの役割
replace は応急処置です。ローカル検証や一時差し替えに限り、恒久化しません。
本流は「構造=go.mod/整合=tidy」。
replace はそれを壊さないための短期手段です。
定義
- 応急処置:一時的に依存の解決先を差し替える(ローカル or 特定版にピン留め)
使うとき
- リリース前の ローカル検証(開発中ブランチを当てたい)
- キャッシュ破損などの 一時的な不具合回避
- 上流のタグ公開待ちで 短期間だけ固定 したい
そもそも使わない
- 長期運用の固定化(将来の更新で破綻しやすい)
- 複数モジュールの接着(必要なら
go workへ) - 依存の機能差分を恒常的に吸収(設計の問題)
推奨運用ルール
- 期限を決める:PRやIssue番号と撤去条件をコメントに明記
- コミットしない:原則ローカルのみ。やむを得ずコミットする場合は即撤去の期限をセット
-
再整合で戻す:
go mod tidy→ 差分確認 →replace撤去
設定例
# 一時的にローカルの修正ブランチへ
replace example.com/lib => ../lib
# タグ公開待ちの短期ピン留め
replace example.com/lib v1.2.3 => example.com/lib v1.2.3-fixed
実務の手順
以下の手順で確認していくことで不整合のリスクを下げることができます。
- tidyの前提を固定(下層の go.mod 排除/vendor・go.sum の不一致解消)
-
go mod tidy実行 →git diff go.mod go.sumで追加/削除のみ確認 - 使っていない
requireを外す。replaceは応急処置のみ(コミットしない)
まとめ
go.mod ファイルはモジュール全体を管理する宣言と位置付けて、依存の追加・削除時にはgo mod tidyで整合性を取りつつ、必要に応じてreplaceで構成が崩れないようにしましょう。
日頃からそう心がけていくことでモジュールの安定性が段違いに向上すると思います。
(相互リンク:本編の背景・設計・考察)
Qiita本編 → https://qiita.com/akio_asano/items/ac3a1f398c2939c96fc7
Discussion