スキップしてメイン コンテンツに移動

【Day 23】【Case 3】本番リリースとタグ打ち(安定バージョンの凍結)

Day 23 アイキャッチ
▲ 【Day 23】本番リリースとタグ打ち(安定バージョンの凍結)
👨‍🏫
皆さん、こんにちは! 本講座の専任講師です。
前回のDay 22では、リリースブランチ(release/v1.0.0)を活用して、次期新機能開発をブロックせずにステージング検証とバグ修正だけを綺麗に収束させる手法を学びました。
本日のDay 23は、第5部 ケーススタディの第3弾として、開発サイクルの集大成である【本番リリースとタグ打ち(安定バージョンの凍結)】を徹底解説します!
Subversion (SVN) や Visual SourceSafe (VSS) で長年開発されてきたベテランエンジニアの方なら、「リリース時に tags フォルダへ丸ごとコピーしたけれど、後から誰かが tags 配下のファイルを直接編集・コミットしてしまい、リリース時と実際のバイナリが一致しなくなった」「リビジョン番号が大きすぎてどのコミットが製品版かわからない」といった苦いトラブルを経験したことがあるはずです。
Gitのタグ機能は、特定コミットに対する「暗号学的に改ざん不可能な不変のピン留め」です。特に「注釈付きタグ(Annotated Tag)」を使えば、リリース担当者の署名・日時・リリースノートがリポジトリ内に永久に記録され、いつでも寸分の狂いもなく過去のリリース状態を100%再現できます。
本日は、検証完了後の安全なmainマージ手順、セマンティックバージョニング(v1.0.0)に基づくタグ打ち、C#のアセンブリバージョン(Directory.Build.props)とGitHub Releasesの自動公開連携、そしてリリース直後に絶対に忘れてはならない「developへのマージバック(先祖返り完全防止)」まで、現場で即座に役立つ実践ノウハウを完全網羅してお届けします!

① 導入・本日の達成目標

結合テストやステージング環境でのQA検証が無事に完了すると、いよいよ製品をエンドユーザーに届ける「本番リリース」を迎えます。
この最終段階で最も求められるのは、「リリースしたコードが絶対に改ざんされず、1年後でも10年後でも寸分違わず同一のビルドを再現できる確実性」です。
Gitのタグ(Tag)とブランチ統合の完全サイクルをマスターすることで、人為的ミスやデグレ(退行バグ)を極限まで排除したプロフェッショナルなリリース体制を構築できます。

🎯 本日のゴール
  • SVNの「タグフォルダコピー(重い・変更可能)」とGitの「コミットへの不変タグ打刻」の本質的違いを腹落ちさせる
  • リリースブランチからmainブランチへの安全なマージ作法(git merge --no-ff)を習得する
  • 「軽量タグ(Lightweight)」と「注釈付きタグ(Annotated)」の違いを理解し、本番リリースには必ず注釈付きタグ(-a)を使う原則を徹底する
  • C# / .NET プロジェクトにおけるバージョン一括管理(Directory.Build.props)とGitHub Releases自動公開の連携フローを理解する
  • mainリリース完了後にバグ修正をdevelopへマージバックし、先祖返り(バグ復活)を100%防止するサイクルを完結させる

② 【図解】SVNのタグコピー vs Gitのタグ打刻:なぜGitのタグは「完全不変」なのか?

まずは、SVNなどの集中型バージョン管理とGitにおける「タグ(Tag)」の決定的な設計思想の違いを確認しましょう。

SVNタグコピー vs Gitタグ打刻
▲ 【図解①】SVNの「フォルダ複製(重い・変更可能)」vs Gitの「不変ピン留め(軽量・改ざん不可)」

SVNにおけるタグは、技術的には「/trunk または /branches のディレクトリを /tags/v1.0.0/ へ丸ごとコピー(svn copy)したもの」に過ぎません。
そのため、運用ルールで「tags配下は変更禁止」と決めていても、うっかり誰かが /tags/v1.0.0/ 内のソースコードを編集してコミットできてしまう重大な脆弱性がありました。
その結果、「本番環境で動いているプログラムと、tagsフォルダのコードが微妙に違う!」という致命的なトラブルが現場で後を絶たなかったのです。

対照的に、Gitのタグは「特定コミットオブジェクトのSHA-1/SHA-256ハッシュ値を指す、不変の参照ポインタ」です。
Gitのコミット履歴は暗号学的なハッシュチェーンで保護されているため、コミット内容や親コミットを1ビットでも書き換えるとハッシュ値が変わります。したがって、タグが指すコードの内容を後から改ざんすることは不可能です。
さらに、実体は数十バイトの参照情報にすぎないため、作成は一瞬(0秒)であり、リポジトリの容量を圧迫することも一切ありません。

📊 SVNタグとGitタグの徹底対比表

比較項目 SVNのタグ(svn copy) Gitのタグ(git tag)
仕組み・実体 別フォルダへの丸ごと複製 特定コミットへの不変ポインタ(0バイト級)
改ざん耐性・不変性 後から編集・コミット可能(危険) 暗号学的ハッシュで完全保護(改ざん不能)
作成速度・負荷 サーバー通信とコピー処理が必要 ミリ秒単位で瞬時に完了
メタデータ記録 SVNコミットログのみ 作成者、作成日時、GPG署名、詳細メッセージ

③ 【図解】mainマージと注釈付きタグ打刻(Annotated Tag)の実践手順

ステージング環境でのQAテストが合格したら、リリースブランチを本番リリース用ブランチ(main)へと統合し、バージョンタグを打刻します。

mainマージと注釈付きタグ打刻フロー
▲ 【図解②】リリース完了からmainマージ、注釈付きタグ(Annotated Tag)打刻までの3ステップ

1. なぜ「軽量タグ」ではなく「注釈付きタグ」を使うのか?

Gitのタグには2種類が存在します。

  • 軽量タグ(Lightweight Tag): git tag v1.0.0 のようにオプションなしで作成。単なるコミットへの別名(エイリアス)であり、作成者や日時のメタデータは一切保持されません。個人開発の一時的なブックマーク用です。
  • 注釈付きタグ(Annotated Tag): git tag -a v1.0.0 -m "メッセージ" で作成。Git内部で独立した「タグオブジェクト」として保存され、作成者の名前・メールアドレス・作成日時・リリースノートメッセージ・(任意で)GPG電子署名が強固に記録されます。
⚠️ 現場の鉄則:本番リリースは必ず git tag -a を使用すること
商用ソフトウェアやWebサービスの本番リリースでは、「誰が・いつ・どのような理由でリリースしたのか」というトレーサビリティ(追跡性)が監査上も極めて重要です。軽量タグを本番リリースに使うことは厳禁と心得ましょう。

2. CLIでの本番マージ&タグ打ちコマンド完全手順

リリースブランチ release/v1.0.0 から main へマージし、タグを打ってプッシュする標準的なコマンドフローです。

# 1. ローカルのmainブランチに切り替え、最新化
git switch main
git pull origin main

# 2. リリースブランチをマージ(必ず --no-ff でマージコミットを記録)
git merge --no-ff release/v1.0.0 -m "Merge branch 'release/v1.0.0' into main for release"

# 3. マージコミットに対して注釈付きタグ(Annotated Tag)を打刻
git tag -a v1.0.0 -m "Release v1.0.0: 正式本番リリース(C# 顧客管理システム新機能・性能改善)"

# 4. mainブランチとタグをリモートリポジトリへプッシュ
git push origin main
git push origin v1.0.0 # または git push --tags

※ git push origin main だけではローカルで作成したタグはリモートに送信されません。必ず git push origin v1.0.0 (または git push origin --tags)を実行してタグを明示的にプッシュする必要があります。

④ 【図解】C#現場でのバージョン管理(Directory.Build.props)とGitHub Releases連携

C#(.NET 8 / .NET 9)の大規模プロジェクトでは、複数のプロジェクト(Web API、Domain、Infrastructure、Batch等)が存在します。
各プロジェクトの .csproj ファイルにそれぞれバージョン番号を手動で記載していると、更新漏れやバージョンの不一致事故が発生します。

C#アセンブリバージョンとGitHub Release連携
▲ 【図解③】Directory.Build.propsの一元定義とGitHub ActionsによるRelease自動公開

1. Directory.Build.props によるソリューション全体の一括バージョン管理

ソリューション(.sln)と同じルートディレクトリに Directory.Build.props ファイルを配置すると、配下のすべての .csproj に自動で共通プロパティが適用されます。

<!-- Directory.Build.props (ソリューションルートに配置) -->
<Project>
  <PropertyGroup>
    <Version>1.0.0</Version>
    <AssemblyVersion>1.0.0.0</AssemblyVersion>
    <FileVersion>1.0.0.0</FileVersion>
    <InformationalVersion>1.0.0+build.release</InformationalVersion>
    <Company>Our Enterprise Tech Inc.</Company>
    <Product>Customer Management System</Product>
  </PropertyGroup>
</Project>

リリース時には、この1箇所の <Version> を 1.0.0 に書き換えてコミットするだけで、全DLLやEXEのアセンブリ情報、SwaggerのAPIバージョン、NuGetパッケージ番号が一括で同期されます!

2. タグプッシュをトリガーとしたGitHub Actions自動リリース連携

git push origin v1.0.0 を行うと、GitHub Actionsが tags: ['v*'] のイベントを検知し、自動的に本番ビルドを実行してGitHub ReleasesにZIP配布物とリリースノートを公開するワークフローが組めます。

# .github/workflows/release.yml
name: Production Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'
      - name: Publish App
        run: dotnet publish -c Release -o ./publish
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          generate_release_notes: true
          files: ./publish/*

⑤ 【図解】developへのマージバックとリリースサイクルの完結

「mainにマージしてタグを打ったから、これで本日のリリース業務は完了!」とPCを閉じてしまっては絶対にダメです!
リリースサイクルにおける最大の落とし穴がここにあります。

developへのマージバックとサイクル完結
▲ 【図解④】developへのマージバックによる先祖返り防止とリリースサイクルの完結

1. なぜ「developへのマージバック」を忘れると悲劇が起きるのか?

Day 22で学んだ通り、リリースブランチ(release/v1.0.0)ではステージング検証中に発見された不具合の緊急修正コミット(fix: ...)や、バージョン番号の更新コミットが行われています。
もしこの修正内容を develop ブランチ(次期バージョン v1.1.0 の開発本流)へ合流させずに放置した場合、何が起きるでしょうか?
次回の v1.1.0 リリース時に、「v1.0.0 で苦労して直したはずのバグが、v1.1.0 で綺麗さっぱり復活する(先祖返り・リグレッション)」という大惨事に見舞われます!

2. サイクルの完結手順(マージバックとブランチ削除)

# 1. developブランチに切り替え、最新化
git switch develop
git pull origin develop

# 2. リリースブランチのバグ修正をdevelopへマージバック
git merge --no-ff release/v1.0.0 -m "Merge branch 'release/v1.0.0' back into develop"
git push origin develop

# 3. mainとdevelop双方への合流が完了したため、役目を終えたリリースブランチを安全に削除
git branch -d release/v1.0.0
git push origin --delete release/v1.0.0

git branch -d (小文字のd)を使えば、対象ブランチが完全にマージされていない場合にエラーで教えてくれるため、誤って未マージのコミットを消してしまう心配もありません。

⑥ 現場で使える!実践CLIコマンド&トラブルシューティング集

📌 タグの一覧確認と詳細情報の表示

git tag -n # タグ名とメッセージを一覧表示
git show v1.0.0 # タグの作成者、日時、メッセージ、コミット差分を詳細表示

git show <tagname> を実行すると、注釈付きタグに付与された電子署名や作成者情報が即座に確認できます。

📌 誤って打ったタグの削除と差し替え手順

git tag -d v1.0.0 # ローカルのタグを削除
git push origin --delete v1.0.0 # リモートリポジトリのタグを削除

※ 一度リモートに公開したタグの削除や差し替えは、他メンバーのローカルキャッシュとの不整合を招くため、チーム内への事前告知を徹底してください。

📌 過去のリリースポイント(タグ)から緊急調査・パッチブランチを作成

git checkout -b hotfix/v1.0.1 v1.0.0 # v1.0.0タグの地点から直接ブランチを派生

本番で重大バグが発生した際も、タグ名を指定するだけで「リリース当時のコードベース」へ一瞬でタイムワープし、緊急ホットフィックスを開始できます。

📌 本日のまとめと次回予告

本番リリースとタグ打刻は、開発チームがユーザーと交わす「品質保証の契約」です。今回の重要ポイントをおさらいしましょう。

  • SVNのタグはただのフォルダコピー(変更可能): Gitのタグは特定コミットを暗号学的に固定する不変のピン留め。
  • 本番リリースは必ず注釈付きタグ(git tag -a): 作成者、日時、詳細メッセージをメタデータとして永久保持する。
  • C#バージョンは Directory.Build.props で一元化: 複数プロジェクトのバージョンズレを防ぎ、タグプッシュからGitHub Releasesを自動生成。
  • developへのマージバックを絶対忘れない: リリースブランチの修正を次期開発本流へ合流させ、先祖返りを100%遮断する。
  • 双方向合流の確認後にブランチ削除: 役目を終えたブランチをクリーンアップし、プロジェクトを常に清潔に保つ。
次回予告【Day 24】: 【Case 4】緊急障害対応(ホットフィックス・パッチリリース)
本番環境で深刻なバグが発生!developや進行中のリリースブランチを一切汚さず、mainのv1.0.0タグから最速でホットフィックスブランチを切り、修正・検証・v1.0.1パッチリリース・全ブランチ統合を完了する「火消しの極意」を徹底伝授します!

コメント

このブログの人気の投稿

【Perfume】Perfume 3rd Tour 「JPN」さいたまスーパーアリーナに行って参りました~

Perfume 3rd Tour 「JPN」1月28日、29日の2daysで参戦して参りました。 ファンクラブ会員の選考抽選会に28日、29日の両日で申し込んでいたんですが、両方とも当選していたという嬉しい誤算。 仕事だぁ、なんだかんだと紆余曲折ありまして28日の参戦は危ぶまれていたのですが、なんとかかんとか28日は40分遅刻しながらも参戦、29日はフル参戦する事が出来ました(∩´∀`)∩

Perfume、2025年末で“コールドスリープ(活動休止)”へ──東京ドーム2daysの記録と、公式・各界・ファンの声

  1) 公式発表・基本情報 活動休止(コールドスリープ)を正式発表 2025年9月21日、公式サイト「 Perfumeより 」で、2026年から一度コールドスリープに入ると発表。再始動の意思(“新しいPerfume”として戻る)も明記。 Perfume Official Site 今後の運用告知(配信・上映など) 同21日付の「 今後のPerfumeに関して 」で、9/23(火・祝)東京ドーム公演の LIVESHIP全世界生配信 および 全国ディレイビューイング 決定を案内。特設サイトも併記。 Perfume Official Site +1 公式グッズ **「Perfume Calendar 2026」**発売決定(B2壁掛け/表紙+2カ月1枚×6枚+ポスター)。テーマは“フルーツ”。 Perfume Official Site 2) 東京ドーム2days(9/22・23)要点 公演タイトル: ZO/Z5 Anniversary “ネビュラロマンス” Episode TOKYO DOME 。日程・開場/開演・会場・物販等の実務情報は特設で公開。 Perfume Official Site 9/23公演を世界配信(LIVESHIP) /ディレイビューイング実施。 Perfume Official Site 海外向け報道(英語)も「 indefinite hiatus 」として広く配信。 The Times of India 国内英字メディアも速報。 朝日新聞 3) 現地レポ( メリ爺 )から見える空気 あなたの現地記録(9/24公開)を、ファクトと現場情景の両面で反映: 両日参戦 。22日は アリーナ 、23日は 1階席から俯瞰 。前日の発表を受け、開演前のザワつき→MC後に“いつもの一体感”へ。開演は22日 18:45 頃。オープニングは**P³ツアー東京ドーム(2020/2)**と同趣向で“回収”の演出。 メリ爺のゲーム万歳 MC所感 :解散ではなく前向きな休止で不安を和らげる内容。 かしゆか の涙、 のっち の気丈さ、 あ〜ちゃん の思い出語り──3人の結束と「 また戻る 」約束が強く刻まれた。 メリ爺のゲーム万歳 体感時間 : “3時間弱”級のボリューム ながら“過去一...

ニンテンドースイッチでオンラインゲームを遊ぶには?

モンスターハンターライズが発売になって、家族でモンハン楽しみたい人が増えたみたいですね。 某ブログの検索キーワードを調べると、モンハンを家族でやるにはどうしたらいいのか?を調べている人が沢山いるのがわかります。 ※これでも一部  家族で協力するにはSwitch2台、ソフトも2つ購入する必要があります。 1台のスイッチでは遊べませんし、ソフト1つでも遊べません。 でも、1台のスイッチで別々アカウントがあれば交代で遊ぶこともできますよ。セーブデータもしっかり分かれます。 Switchのオンラインゲームを家族で遊ぶ方法については以下の記事にまとめてますのでよろしければ参考にしてみてくださいね。 家族でモンスターハンターライズDL版のオンラインプレーを楽しむ方法