🥲

【Go】タグを付け直したら `@main` や `@latest` で内容が入らなくなった話

に公開

はじめに

GoモジュールをGitHubで公開しているとき、
タグを付け直しただけで @main すらインストールできなくなる
という不思議な現象に遭遇しました。

単なるキャッシュの問題かと思いきや、Goのモジュールまわりの仕組みが深く関係していました。
本記事ではその原因と対処法をまとめます。


現象

あるCLIツールをGitHubに公開し、以下のようにインストールできていました。

go install github.com/tonbiattack/git-plus-go/cmd/git-newbranch@main
# または
go install github.com/tonbiattack/git-plus-go/cmd/git-newbranch@latest

ここまでは正常。
ところが、以下のコマンドでリリースタグを付け直した後、
新しくコードを追加してそのタグに含めたにもかかわらず、再インストールしようとすると…

# ローカルタグ削除
git tag -d v1.0.0

# リモートタグ削除
git push --delete origin v1.0.0

# 最新コミットにタグ付け直し
git tag v1.0.0

# リモートにタグをプッシュ
git push origin v1.0.0

このようにタグを付け直した直後から、以下のようなエラーが出るようになりました。

特に問題だったのは、新しく追加した git-amend コマンドがタグに含まれているにもかかわらず、インストールできなくなったことです。

go install github.com/tonbiattack/git-plus-go/cmd/git-amend@latest
go: github.com/tonbiattack/git-plus-go/cmd/git-amend@latest: module github.com/tonbiattack/git-plus-go@latest found (v1.0.0), but does not contain package github.com/tonbiattack/git-plus-go/cmd/git-amend

あるいは

verifying module: checksum mismatch
SECURITY ERROR

といったエラーが出て、
リポジトリに確かに存在する(そしてタグにも含まれているはずの)ソースが取れなくなるという謎状態になりました。


なぜ @main でも入らなくなるのか?

Go のモジュール解決は単純そうに見えて、実はキャッシュやチェックサムDBを強く利用しています。
この問題の核心は次の3点です。

1. Goはタグの中身を「不変」として扱う

一度タグ(例:v1.0.0)を切ると、そのZIPのハッシュが
sum.golang.org(チェックサムDB)に永久保存されます。

同じタグ名で中身を変える(付け直す)と:

sum.golang.org に登録されたハッシュと、GitHub の新しいZIPのハッシュが一致しない

となり、**「改ざん扱い」**で拒否されます。


2. mainブランチも「古いタグを参照」してしまうことがある

Go の @main は単にブランチ名ではなく、
**擬似バージョン(例:v1.0.1-0.20251106-xxxx)**として扱われます。

これを生成するとき、内部的には「最新のタグをベース」にしてバージョンを決めるため、
壊れた v1.0.0 が参照され続けることがあります。

つまり:

タグを付け直すと、そのタグが main のバージョン解決にまで影響してしまう。


3. キャッシュも更新されない

Goは $GOPATH/pkg/mod にモジュールZIPをキャッシュします。
タグを書き換えても、そのZIPを信じ続けるため、
最新のmainを取りに行かず、古いZIPを使い続けることも原因になります。


対処法

✅ 理想的な解決策:タグを付け直さず、新しいタグを切る

git tag v1.0.1
git push origin v1.0.1

そして:

go install github.com/tonbiattack/git-plus-go/cmd/git-amend@latest

これで @latest は自動的に v1.0.1 を解決します。
(Goの仕様上、@latest は最新タグまたは main HEAD を取ります)


🧹 試したがダメだった対処法

以下の方法を様々な組み合わせで試してみましたが、結局解決できませんでした:

キャッシュのクリア

go clean -modcache
go clean -cache
go clean -modcache -cache

何度もキャッシュをクリアして再インストールを試みましたが、状況は変わりませんでした。

プロキシとチェックサムの設定変更

# PowerShellの場合
$env:GOPROXY = "direct"
$env:GONOSUMDB = "github.com/tonbiattack/*"

# Bashの場合
GOPROXY=direct go install github.com/tonbiattack/git-plus-go/cmd/git-squash@main

GOPROXY=direct でGitHubから直接取得を試みたり、GONOSUMDB でチェックサム検証を回避しようとしましたが、効果がありませんでした。

異なるバージョン指定での試行

go install github.com/tonbiattack/git-plus-go/cmd/git-squash@main
go install github.com/tonbiattack/git-plus-go/cmd/git-squash@latest
go install github.com/tonbiattack/git-plus-go/cmd/git-squash@v1.0.0
go install github.com/tonbiattack/git-plus-go/cmd/git-squash@v1.0.1
go install github.com/tonbiattack/git-plus-go/cmd/git-squash  # バージョン指定なし

@main、@latest、特定のタグ、バージョン指定なしなど、あらゆるパターンを試しましたが、いずれも失敗しました。

タグの削除と再作成

git tag -d v1.0.0
git push origin :refs/tags/v1.0.0
git tag v1.0.0
git push origin v1.0.0

GitHubからタグを完全に削除して再作成しても、sum.golang.org に登録された古いハッシュとの不整合は解消されませんでした。


💥 最終的な解決策:リポジトリの作り直し

色々試行錯誤しましたが、最終的にはリポジトリを作り直すことで解決しました。

sum.golang.org のチェックサムデータベースは、一度登録されたハッシュは永久に削除・変更できない仕様になっています。
これは Transparent Log(Merkle Tree)として実装されており、改ざん検出のために独立した監査者が検証できる設計になっているためです。

「問題のあるタグだけを削除する方法はないのか?」と調べましたが、
Go公式ドキュメントにも明記されている通り、そのような方法は理論的にも存在しません。

タグを付け直してしまった場合、以下の選択肢しかありません:

  1. 新しいバージョンタグを切る(推奨): v1.0.1、v1.0.2のように新しいタグで進める
  2. リポジトリを作り直す(最終手段): モジュールパスを変更して新規リポジトリを作成

今回は後者を選択し、新しいリポジトリを作成することで問題を解決しました。

https://github.com/tonbiattack/git-plus


🚫 タグを付け直してはいけない理由(再掲)

操作 Goの挙動
同じタグ名を再利用 sum.golang.org との整合性が崩れ、永久にNG
タグ削除 → 再push 依然として過去のハッシュが残る
mainブランチ変更 擬似バージョン生成に古いタグが影響する
force-push キャッシュが古いZIPを保持している可能性あり

教訓

  • タグは「不変のスナップショット」として扱われ、一度公開したら変更不可
  • 修正したいときは「タグを付け直す」ではなく「新しいタグを切る」
  • @main も内部的にはタグの影響を受けるので油断しない
  • タグを付け直してしまった場合、キャッシュクリアなどでは解決できない
  • 最悪の場合、リポジトリの作り直しが必要になる

まとめ

Goの世界では「タグは歴史」であり、「上書き」は改ざん扱い。

タグを付け直した瞬間、main ですら信頼されなくなる──
これは一見理不尽ですが、「再現性のあるビルド」を守るための設計です。

今回のケースでは、新しいコードを追加してタグに含めたにもかかわらず、
sum.golang.org に登録された古いハッシュとの不整合により、インストールできなくなりました。
様々な対処法を試みましたが、結局リポジトリを作り直すという結末になりました。

教訓:Goモジュールのタグは絶対に付け直さない。どうしても必要なら新しいリポジトリを作る覚悟で。


参考リンク

Discussion