メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

挙動変更

go.modで`go 1.27`以上を指定するモジュールでは、`go mod tidy`がrequireブロックを直接依存・間接依存の最大2ブロックに自動統合するようになった

go mod tidy

この項目の注釈は AI により生成されており、誤りを含む場合があります。

概要

go.modファイルでgo 1.27以上を指定しているモジュールでは、go mod tidyがrequireブロックを自動的に統合するようになった。これにより、go.modは常に「直接依存用の1ブロック」と「間接依存用の1ブロック」の、最大2ブロックというクリーンな構造に保たれる。依存関係に付与されていた既存のコメントブロックは統合後も保持され、直接依存と間接依存が混在するブロックにコメントが付いていた場合は、そのコメントは統合後の直接依存ブロック側に引き継がれる。

手動編集や解消しきれなかったGitマージコンフリクト、古いバージョンからのアップグレードなどが原因でgo.modに3つ以上の分散したrequireブロックが蓄積してしまうことが以前からあったが、従来のgo mod tidyはこれらの余分なブロックをそのまま残す(あるいは意図せず新たなブロックを作ってしまう)ことがあった。今回の変更により、go mod tidyは2ブロックのレイアウトを厳格に強制し、散らばった依存関係をそれぞれのブロックへ統合してファイル構造を自動的に整理する。

導入経緯

本項目はgolang/go#56471の提案に基づく。提案者は、go.modが3つ以上のrequireブロックを持つ実例(手動マージ解消やgo get/go mod edit使用時に発生)を複数報告し、go mod tidyがこれらを1つに統合すべきだと提起した。

議論のハイライト

  • コントリビューターから、goディレクティブがgo 1.16からgo 1.17の境界をまたぐ際の移行の癖(quirk)がこの問題に関係しているのではないかという指摘があった。
  • 複数の利用者が独立に、go mod tidyが2ブロック構成のファイルに対してさえ意図せず3つ目のrequireブロック(直接・間接混在)を作ってしまう再現手順を報告し、これは提案とは別の不具合としてgolang/go#67948で追跡されることになった。
  • レビュアーからは、3ブロック構成を意図的に必要とするユースケースが実際に存在するかどうかを確認すべきという論点が示され、module proxy上のgo.modを分析する案も出た。
  • 最終的にコメントでhttps://go.dev/cl/738740https://go.dev/cl/739061(cmd/go: simplify go.mod to have at most two require sections)、https://go.dev/cl/739221(x/mod: allow for aggressively consolidating requires)が本Issueに関連付けられ、実装に至った。

移行時の注意

  • go.modgoディレクティブがgo 1.27未満のモジュールでは、従来通りの挙動(go 1.17以上なら直接・間接の2ブロックへの分離のみ。ブロックにコメントが付いている場合は移動しない)が維持される。挙動が変わるのはgo 1.27以上を宣言した場合のみ。
  • 混在ブロック(直接・間接が混在)にコメントが付いていた場合、そのコメントは統合後は直接依存ブロック側に引き継がれる。間接依存専用のコメントを混在ブロックに書いていた場合は、意図しない位置にコメントが移動する可能性があるため確認するとよい。
  • 3ブロック以上に依存関係を意図的に分割・整理して管理していたgo.modがある場合、go 1.27へ上げてgo mod tidyを実行すると、その構造は強制的に2ブロックへ統合される。

実装解説

go mod tidyが生成するgo.modのrequireブロック構造は、modload/init.goで、モジュールが宣言するgoバージョンに応じて3段階に分岐している。

  • goバージョンがgover.SeparateIndirectVersion("1.17")未満: File.SetRequireでブロック構造を変更せず維持する。
  • gover.SimplifyRequireVersion("1.27"version.go:47)未満: File.SetRequireSeparateIndirectで直接・間接の2ブロックへ分離するが、コメント付きの既存ブロックには手を出さない。
  • 1.27以上: 新設されたFile.SetRequireAtMostTwo(modfile/rule.go:1279)を呼び、既存のブロック構造やコメントの有無を無視して常に最大2ブロックへ強制的に統合する。

SetRequireAtMostTwoは内部的に共通関数setRequireSeparateIndirect(req, simplify)(rule.go:1286)をsimplify=trueで呼び出す実装になっている。simplifyが真の場合、各requireブロックの前置コメント(Comments.Before)はそのブロックの内容がすべて間接依存かどうかで振り分けられ(directBlockComments/indirectBlockCommentsrule.go:1392-1409)、既存の行がどのブロックに属していたかに関わらず最終的な直接・間接ブロックへ強制的に移動される(rule.go:1496-1502)。

関連リンク