Squash mergeでgitタグが孤立する — git describeで検出できなくなる原因と対策

Squash mergeでgitタグが孤立する — git describeで検出できなくなる原因と対策

squash mergeでフィーチャーブランチに打ったgitタグが孤立し、git describeで検出できなくなる問題の原因と対策を解説。タグはsquash merge後にmain上で打つのが正解。
2026.07.10

GitHub の squash merge を使っていたら git describe --tags --abbrev=0 で最新タグが見つからなくなりました。原因はフィーチャーブランチで打ったタグが squash merge で孤立すること。再現手順、診断方法、対策をまとめます。

前提・環境

  • Git 2.49
  • GitHub(PR の squash merge を使用)
  • リリース自動化スクリプトで git describe --tags によるバージョン検出を使用

何が起きたか

リリース自動化スクリプトでバージョンを取得するために以下のコマンドを使っていました。

CURRENT=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")

v0.6.3 をリリースしたはずなのに、このコマンドが v0.6.0 を返す。v0.6.1v0.6.2v0.6.3 のタグが見つからない状態でした。

原因: squash merge によるタグの孤立

リリースフローの問題

当時のリリースフローは以下の順序でした。

  1. フィーチャーブランチで実装
  2. バージョンバンプコミット
  3. フィーチャーブランチ上でタグを作成 (git tag v0.6.3)
  4. ブランチとタグをpush
  5. PR作成 → squash merge

squash merge が何をするか

squash merge は、フィーチャーブランチの全コミットを1つにまとめた新しいコミットを main 上に作成します。

squash-merge-orphans-git-tags-squash-orphan

重要なのは、squash merge コミット SC とは異なるSHAだということです。タグ v0.6.3 はコミット C を指していますが、C は main の祖先(ancestor)には存在しません。

git describe の動作

git describe --tags --abbrev=0 は、現在のコミットの祖先をたどって最初に見つかるタグを返します。main 上で実行すると X → Y → Z → S の祖先しかたどらないため、コミット C に付いたタグは見つかりません。

# main 上で実行
$ git describe --tags --abbrev=0
v0.6.0  # v0.6.1, v0.6.2, v0.6.3 は見つからない

これがタグの「孤立」です。タグ自体は存在していますが、main のコミット履歴からは到達できません。

診断方法

タグが孤立しているか確認する

# タグが指すコミットが main の祖先にあるか確認
git merge-base --is-ancestor $(git rev-parse v0.6.3) main
echo $?  # 0 = 祖先にある, 1 = 孤立している

全タグの孤立状況を一覧表示

for tag in $(git tag --sort=-v:refname); do
  if git merge-base --is-ancestor "$(git rev-parse "$tag")" main 2>/dev/null; then
    echo "OK   $tag"
  else
    echo "ORPHAN $tag"
  fi
done

実行結果:

ORPHAN v0.6.3
ORPHAN v0.6.2
ORPHAN v0.6.1
OK   v0.6.0
OK   v0.5.0

タグとコミットの関係を確認

# タグが指すコミットのSHA
git rev-parse v0.6.3

# main の最新コミットのSHA(squash merge コミット)
git rev-parse main

# 異なるSHAが表示される → タグが main 上にない

対策: タグは squash merge 後に main 上で打つ

修正後のフロー

  1. フィーチャーブランチで実装
  2. バージョンバンプコミット(タグはまだ打たない
  3. ブランチをpush、PR作成
  4. squash merge
  5. main をチェックアウトしてpull
  6. squash merge コミット上でタグを作成
  7. タグをpush
# PR を squash merge した後
git checkout main
git pull origin main

# squash merge コミット上でタグを打つ
git tag v0.6.3
git push origin --tags

こうすれば、タグは確実に main の履歴上のコミットを指します。

squash-merge-orphans-git-tags-fixed-flow

既存の孤立タグを修復する

既に孤立してしまったタグは、git tag -f で main 上の正しいコミットに付け替えられます。

まず、各タグに対応する squash merge コミットを特定します。

# squash merge コミットのメッセージにはPR番号が含まれるので、それで特定
git log --oneline main | head -20

対応するコミットが見つかったら付け替えます。

# ローカルでタグを付け替え
git tag -f v0.6.3 <squash-merge-commit-sha>
git tag -f v0.6.2 <squash-merge-commit-sha>
git tag -f v0.6.1 <squash-merge-commit-sha>

# リモートに強制push
git push origin --tags --force

修復後の確認:

$ git describe --tags --abbrev=0
v0.6.3  # 正しく検出される

$ for tag in v0.6.{1,2,3}; do
    git merge-base --is-ancestor "$(git rev-parse "$tag")" main && echo "OK $tag" || echo "ORPHAN $tag"
  done
OK v0.6.1
OK v0.6.2
OK v0.6.3

通常の merge では起きない

通常の merge(non-squash)ではフィーチャーブランチのコミットが main の祖先に含まれるため、この問題は発生しません。

squash-merge-orphans-git-tags-normal-merge

merge コミット M から C へたどれるので、git describe でタグが見つかります。

rebase merge も同様に問題が起きます。rebase はコミットを cherry-pick するため、新しいSHAが生成されます。

merge 方式 タグが孤立するか
通常 merge しない
squash merge する
rebase merge する

まとめ

  • squash merge はフィーチャーブランチのコミットとは異なるSHAの新コミットを main 上に作る
  • フィーチャーブランチで打ったタグは main の祖先から到達できず、git describe で検出できなくなる
  • 対策: タグは squash merge 後に main 上で打つ
  • git merge-base --is-ancestor でタグの孤立を診断できる
  • 孤立済みのタグは git tag -f で main 上のコミットに付け替え可能

リリース自動化で git describe --tags を使っている場合、squash merge との組み合わせには注意が必要です。

参考

この記事をシェアする

関連記事