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

Gitで青い画面が出たら? 対応図解備忘録 マージコミットの書き方(新人エンジニア向け)


    画像
    画像
    画像

    merge branch hogehoge を実行したときに出るメッセージ入力プロンプト(please enter a commit to ecplain why this merge is necessary ...)の意味と、「何を書けば良いか」「なぜ重要か」「実例」 を分かりやすく


    初めてのマージでも迷わないよう、テンプレート・良い例・悪い例・運用ルールまでカバーします。


    1. なぜマージコミットに意味のあるメッセージが必要か?

    • 他の人(将来の自分含む)が変更の目的を短時間で理解できる。

    • CI/リリース履歴やバグ調査で「いつ・なぜ」その変更が入ったか追える。

    • 特に 「上流(upstream)の更新をトピックブランチに取り込む」 場合は、競合解決や再現手順の説明が重要。


    2. Git のプロンプトに書かれている意味(日本語で簡単に)

    please enter a commit to explain why this merge is necessary
    especially if merges an updated upstream into a topic branch.
    Line starting with '#' will be ignored, and an empty message aborts the commit
    
    • 「このマージが必要な理由を書く」:何を取り込んだのか・なぜ取り込んだのかを説明してね、という指示です。

    • 「特に upstream の更新を topic ブランチにマージする場合は詳細に」:上流の変更が原因で挙動が変わりうるので、何が更新されたかを書くと親切。

    • # で始まる行はコメントとして無視される(テンプレートや説明行)。

    • 空のメッセージにするとコミットは中止される(誤って空コミットするのを防ぐ)。


    3. マージコミットの基本フォーマット(推奨)

    短い要約(50文字以内)
    
    何をしたか/なぜしたか(理由、背景、影響)
    - 何をマージしたか(例: origin/main を hogehoge に取り込んだ)
    - 目的(例: 依存ライブラリの脆弱性修正を取り込むため)
    - コンフリクトの有無と、解決方法(あれば簡潔に)
    - テスト結果(ローカルでの確認、CI通過など)
    
    関連チケット/PR: #123 , PR: https://...
    

    ポイント

    • 1行目は「タイトル」:何をしたかが一目で分かる短文に。

    • 2行目は空行で区切る。

    • 本文では「why(なぜ)」「what(何を)」「how(どうやって)」「verify(確認方法)」を書く。

    • 可能なら関連チケットやPR番号を入れる。


    4. 具体例(よくあるパターン)

    A. upstream(main)を topic ブランチにマージする場合

    Merge branch 'origin/main' into hogehoge
    
    取り急ぎ upstream の main を取り込み、依存パッケージの更新とセキュリティ修正を反映しました。
    - 取り込んだ内容: main のコミット  abc123..def456(依存: lib-xyz 1.2.3 -> 1.2.4)
    - 目的: CI のテストエラー解消およびセキュリティパッチ適用
    - コンフリクト: src/config.yml の設定差分を main 側に合わせる形で解決
    - 確認: ローカルで unit tests 全通(`npm test`), lint OK
    
    関連: PR #45 , JIRA-789
    

    B. トピックブランチ同士をマージ(機能統合)

    Merge branch 'feature/login' into develop
    
    feature/login を develop に統合。ログインフローの UI/UX を統合するため。
    - 主な変更: OAuth2 ログイン実装、セッション周りの修正
    - コンフリクト: session-manager.js の競合を feature/login の実装優先で解決
    - テスト: e2e テスト(ログイン成功/失敗)を確認済み
    
    関連 PR: #88 
    

    C. 悪い例(NG)

    Merge branch 'hogehoge'
    

    → 何を取り込んだか・なぜか全く分からない。将来の調査で困る。


    5. コンフリクトがあった場合は必ず書く

    コンフリクトを手で直したら、どこをどう直したかは必ず本文に書きます。
    例:「app/config.yml の DB 接続設定は main のものを採用」「utils/parse.js はトピック側のロジックを残した」など。
    理由:後から見たときに「なぜその差分になっているのか」が分かるからです。


    6. 実務運用のTips(チームルール例)

    • マージは --no-ff(明示的なマージコミット)で残す:履歴が分かりやすくなる。
      git merge --no-ff feature/foo -m "Merge branch 'feature/foo' into develop: <summary>"

    • 小さな変更であれば squash merge も可。ただし squash の場合はマージ時に PR の説明をちゃんと残す。

    • メッセージはテンプレ化しておく(CI の自動生成やレビューで使いやすくなる)。

    • 重要なマージ(アップデート・セキュリティ)には必ずレビューを通す。


    7. エディタでの操作メモ(補足)

    • Git がエディタを開いたときは、上部のテンプレート(# 始まり)を無視して本文を書きます。

    • 保存してエディタを閉じるとコミットが実行されます。

    • 空行にして保存・終了するとコミットは中止されます(abort)。

    • コマンドラインで直接メッセージを付けるなら:

      1. git merge --no-ff hogehoge -m "Merge branch 'hogehoge' into develop hogehoge の変更を統合。foo のバグ修正を取り込み、bar の挙動を調整。コンフリクト箇所: src/a.js(hogehoge を採用)"


    8. まとめチェックリスト(コミット前に確認)

    • 1行目で何をしたかが分かるか(50字以内)

    • なぜこのマージが必要かを書いたか(理由)

    • コンフリクトがあれば解決方法を記載したか

    • テストや確認方法を書いたか(CI やローカルの確認)

    • 関連チケット/PR を記載したか


    良いですね 👍
    以下は、新人エンジニアがマージ時にそのままエディタに貼って使える Gitマージコミットメッセージテンプレート(Qiita風・実務向け) です。
    Visual Studio Code や Vim、Git の commit.template 設定にもそのまま利用できます。


    🧩 Git Merge Commit Template(マージコミットテンプレート)

    # ==========================================================
    # 🧩 Merge Commit Template
    # このマージが「何を」「なぜ」行うのかを明確に書く!
    # (# から始まる行はコメントとして無視されます)
    # ==========================================================
    
    Merge branch '<ブランチ名>' into <統合先ブランチ>
    
    <1行で要約(50文字以内): このマージの目的を簡潔に説明>
    
    <空行>
    
    【目的・背景】
    - 例:上流ブランチ(main)の更新を取り込み、依存パッケージの脆弱性修正を反映するため。
    - 例:feature/login の実装を develop に統合し、ログイン機能をテスト可能にするため。
    
    【取り込んだ内容】
    - 対象コミット: <コミットID範囲やPR番号>
    - 主な変更点:
      - <ポイント1>
      - <ポイント2>
    
    【コンフリクト対応】
    - 発生箇所: <ファイル名1>, <ファイル名2>
    - 対応方針:
      - <どちらのブランチの内容を採用したか>
      - <理由>
    
    【動作確認・テスト】
    - [ ] ローカルでビルド成功
    - [ ] 単体テスト通過
    - [ ] CI/CD パイプライン成功
    - [ ] 主要機能(例: ログイン/注文)手動確認済み
    
    【備考・関連リンク】
    - 関連PR/Issue: #<番号>
    - 関連チケット: <JIRA/Trello等のID>
    - メモ: <補足があれば>
    
    # ----------------------------------------------------------
    # Tips:
    # - 1行目は短く簡潔に(タイトルとして表示される)
    # - 背景・理由を具体的に書くとレビューや将来の解析に役立つ
    # - 空のメッセージで保存するとマージが中止されます
    # ----------------------------------------------------------
    

    🛠️ 設定方法(任意)

    このテンプレートを .gitmessage-merge.txt などの名前でプロジェクト直下に保存し、
    Git にデフォルトテンプレートとして登録できます👇

    git config --global commit.template ~/.gitmessage-merge.txt
    

    以後、マージ時に自動でこのテンプレートが開かれます。


    HTML版

    # Phase 8: push(GitHubリポジトリ作成後)<br>
    git remote add origin https://github.com/ユーザー名/git-3min-practice.git<br>
    git push -u origin main<br>
    git push --all<br><br>
    # 履歴確認<br>
    git log --graph --oneline --all
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'mkdir git-3min-practice && cd git-3min-practice\ngit init\necho \"# 3分Git実践\" > README.md\ngit add README.md\ngit commit -m \"Initial commit\"\ngit checkout -b featureA\necho \"機能A - パート1\" > featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート1を追加\"\necho \"機能A - パート2\" >> featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート2を追加\"\ngit checkout main\necho \"メイン作業 - その1\" > main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業1を追加\"\necho \"メイン作業 - その2\" >> main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業2を追加\"\ngit checkout -b featureB\necho \"機能B - 開始\" > featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 開始\"\necho \"機能B - 完了\" >> featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 完了\"\ngit checkout featureA\ngit rebase main\ngit checkout featureB\ngit revert HEAD --no-edit\ngit checkout main\ngit merge featureA\ngit merge featureB\ngit log --graph --oneline --all')">コピー</button>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>🔥 緊急対応:</strong> マージコミットメッセージエディタが開いた時</span>
                    </div>
    
                    <div class="warning">
                        <h3 style="color:#721c24; margin-bottom:10px;">❓ こんな画面が出ましたか?</h3>
                        <div class="output-box">
    Merge branch 'hogehoge'<br>
    <br>
    # Please enter a commit message to explain why this merge is necessary,<br>
    # especially if it merges an updated upstream into a topic branch.<br>
    #<br>
    # Lines starting with '#' will be ignored, and an empty message<br>
    # aborts the commit.
                        </div>
                    </div>
    
                    <div class="note">
                        <h3 style="margin-bottom:10px;">💡 これは何?</h3>
                        <p>Git が自動的にエディタ(Vi/Vim)を開いて、マージの理由を書くように求めています。</p>
                    </div>
    
                    <div class="success">
                        <h3 style="margin-bottom:15px;">✅ 対処法:3つの方法</h3>
    
                        <div style="background:white; padding:15px; border-radius:8px; margin:15px 0;">
                            <h4 style="color:#155724; margin-bottom:10px;">方法1: そのまま保存して終了(デフォルトのメッセージを使用)</h4>
                            <div class="command-container">
                                <div class="command-box">
    # Viエディタの場合<br>
    :wq<br>
    <span style="color:#ffc107;"># または</span><br>
    :x
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, ':wq')">コピー</button>
                            </div>
                            <p style="margin-top:10px; color:#666;">
                                <strong>手順:</strong><br>
                                1. キーボードで <code>:</code> を押す(コロン)<br>
                                2. <code>wq</code> と入力<br>
                                3. <kbd>Enter</kbd> を押す
                            </p>
                        </div>
    
                        <div style="background:white; padding:15px; border-radius:8px; margin:15px 0;">
                            <h4 style="color:#155724; margin-bottom:10px;">方法2: メッセージを編集してから保存</h4>
                            <div class="command-container">
                                <div class="command-box">
    # 1. 'i' を押して編集モードに入る<br>
    i<br><br>
    # 2. メッセージを入力(例)<br>
    Merge branch 'featureB' into main<br>
    <br>
    featureBの新機能をmainに統合<br>
    - 機能Bの実装完了<br>
    - テスト済み<br><br>
    # 3. ESCキーを押して編集モード終了<br>
    <span style="color:#ffc107;">[ESC]</span><br><br>
    # 4. 保存して終了<br>
    :wq
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, 'i\n[メッセージ入力]\n[ESC]\n:wq')">コピー</button>
                            </div>
                        </div>
    
                        <div style="background:white; padding:15px; border-radius:8px; margin:15px 0;">
                            <h4 style="color:#155724; margin-bottom:10px;">方法3: キャンセルして中止</h4>
                            <div class="command-container">
                                <div class="command-box">
    # マージを中止する<br>
    :q!
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, ':q!')">コピー</button>
                            </div>
                            <p style="margin-top:10px; color:#666;">
                                <strong>注意:</strong> マージ自体がキャンセルされます
                            </p>
                        </div>
                    </div>
    
                    <div class="warning">
                        <h3 style="color:#721c24; margin-bottom:10px;">⚠️ Viエディタが苦手な場合</h3>
                        <p style="margin-bottom:10px;">今後エディタが開かないようにする方法:</p>
                        
                        <div style="background:white; padding:15px; border-radius:8px; margin:10px 0;">
                            <strong>オプション1: mergeコマンドで直接メッセージを指定</strong>
                            <div class="command-container">
                                <div class="command-box">
    git merge featureB -m "featureBをmainに統合"
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, 'git merge featureB -m \"featureBをmainに統合\"')">コピー</button>
                            </div>
                        </div>
    
                        <div style="background:white; padding:15px; border-radius:8px; margin:10px 0;">
                            <strong>オプション2: デフォルトエディタを変更</strong>
                            <div class="command-container">
                                <div class="command-box">
    # VS Codeに変更<br>
    git config --global core.editor "code --wait"<br><br>
    # または、メモ帳に変更(Windows)<br>
    git config --global core.editor "notepad"
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, 'git config --global core.editor \"code --wait\"')">コピー</button>
                            </div>
                        </div>
    
                        <div style="background:white; padding:15px; border-radius:8px; margin:10px 0;">
                            <strong>オプション3: --no-editオプション(デフォルトメッセージ使用)</strong>
                            <div class="command-container">
                                <div class="command-box">
    git merge featureB --no-edit
                                </div>
                                <button class="copy-btn" onclick="copyCommand(this, 'git merge featureB --no-edit')">コピー</button>
                            </div>
                        </div>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>📚 参考:</strong> Viエディタ基本コマンド</span>
                    </div>
    
                    <table>
                        <thead>
                            <tr>
                                <th>コマンド</th>
                                <th>説明</th>
                                <th>使用場面</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td><code>i</code></td>
                                <td>編集モードに入る(Insert)</td>
                                <td>テキストを入力する前</td>
                            </tr>
                            <tr>
                                <td><code>ESC</code></td>
                                <td>編集モードを終了</td>
                                <td>入力が終わった後</td>
                            </tr>
                            <tr>
                                <td><code>:wq</code></td>
                                <td>保存して終了(Write & Quit)</td>
                                <td>編集が完了した時</td>
                            </tr>
                            <tr>
                                <td><code>:x</code></td>
                                <td>保存して終了(:wq と同じ)</td>
                                <td>編集が完了した時</td>
                            </tr>
                            <tr>
                                <td><code>:q!</code></td>
                                <td>保存せずに終了(強制)</td>
                                <td>変更を破棄したい時</td>
                            </tr>
                            <tr>
                                <td><code>:w</code></td>
                                <td>保存(終了しない)</td>
                                <td>途中で保存したい時</td>
                            </tr>
                            <tr>
                                <td><code>dd</code></td>
                                <td>1行削除</td>
                                <td>不要な行を消す時</td>
                            </tr>
                            <tr>
                                <td><code>u</code></td>
                                <td>元に戻す(Undo)</td>
                                <td>間違えた時</td>
                            </tr>
                            <tr>
                                <td><code>yy</code></td>
                                <td>1行コピー</td>
                                <td>行をコピーしたい時</td>
                            </tr>
                            <tr>
                                <td><code>p</code></td>
                                <td>貼り付け</td>
                                <td>コピーした内容を貼る時</td>
                            </tr>
                        </tbody>
                    </table>
    
                    <div class="note" style="margin-top:20px;">
                        <h3 style="margin-bottom:10px;">💡 覚えるべき最重要コマンド</h3>
                        <ol style="margin-left:20px;">
                            <li style="margin:8px 0;"><strong>i</strong> → 編集開始</li>
                            <li style="margin:8px 0;"><strong>ESC</strong> → 編集終了</li>
                            <li style="margin:8px 0;"><strong>:wq</strong> → 保存して終了</li>
                            <li style="margin:8px 0;"><strong>:q!</strong> → 保存せず終了</li>
                        </ol>
                        <p style="margin-top:10px;">この4つだけ覚えれば大丈夫!</p>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>📝 まとめ:</strong> マージコミットメッセージのベストプラクティス</span>
                    </div>
    
                    <div class="note">
                        <h3 style="margin-bottom:10px;">良いマージコミットメッセージの例</h3>
                        <div class="command-container">
                            <div class="command-box" style="color:#e2e8f0;">
    Merge branch 'feature/user-authentication' into main<br>
    <br>
    ユーザー認証機能をmainブランチに統合<br>
    <br>
    ## 変更内容<br>
    - ログイン機能の実装<br>
    - パスワードリセット機能<br>
    - セッション管理<br>
    <br>
    ## テスト<br>
    - 単体テスト: 全て通過<br>
    - 統合テスト: 正常系・異常系確認済み<br>
    <br>
    ## レビュー<br>
    Reviewed-by: Tanaka Taro<br>
    Closes #123 
                            </div>
                            <button class="copy-btn" onclick="copyCommand(this, 'Merge branch \'feature/user-authentication\' into main\n\nユーザー認証機能をmainブランチに統合\n\n## 変更内容\n- ログイン機能の実装\n- パスワードリセット機能\n- セッション管理\n\n## テスト\n- 単体テスト: 全て通過\n- 統合テスト: 正常系・異常系確認済み\n\n## レビュー\nReviewed-by: Tanaka Taro\nCloses #123 ')">コピー</button>
                        </div>
                    </div>
    
                    <div class="note">
                        <h3 style="margin-bottom:10px;">シンプルな例(小規模な変更)</h3>
                        <div class="command-container">
                            <div class="command-box" style="color:#e2e8f0;">
    Merge branch 'featureB' into main<br>
    <br>
    機能Bを追加
                            </div>
                            <button class="copy-btn" onclick="copyCommand(this, 'Merge branch \'featureB\' into main\n\n機能Bを追加')">コピー</button>
                        </div>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>🎯 完全版:</strong> 実行コマンド全体フロー</span>
                    </div>
    
                    <div class="command-container">
                        <div class="command-box" style="max-height:500px; overflow-y:auto; line-height:1.8;">
    <span style="color:#ffc107;"># ===== Phase 0: 準備 =====</span><br>
    mkdir git-3min-practice<br>
    cd git-3min-practice<br>
    git init<br>
    echo "# 3分Git実践" > README.md<br>
    git add README.md<br>
    git commit -m "Initial commit"<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 1: featureAブランチで2回コミット =====</span><br>
    git checkout -b featureA<br>
    echo "機能A - パート1" > featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート1を追加"<br>
    echo "機能A - パート2" >> featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート2を追加"<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 2: mainブランチで2回コミット =====</span><br>
    git checkout main<br>
    echo "メイン作業 - その1" > main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業1を追加"<br>
    echo "メイン作業 - その2" >> main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業2を追加"<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 3: featureBブランチで2回コミット =====</span><br>
    git checkout -b featureB<br>
    echo "機能B - 開始" > featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 開始"<br>
    echo "機能B - 完了" >> featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 完了"<br>
    <br>
    <span style="color:#ffc107;"># ===== 履歴確認 =====</span><br>
    git log --graph --oneline --all<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 4: rebase(featureAを一直線に) =====</span><br>
    git checkout featureA<br>
    git rebase main<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 5: revert(featureBのコミット取り消し) =====</span><br>
    git checkout featureB<br>
    git revert HEAD --no-edit<br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 6: merge(featureAをmainに統合) =====</span><br>
    git checkout main<br>
    git merge featureA  <span style="color:#68d391;"># Fast-forward マージ</span><br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 7: merge(featureBをmainに統合) =====</span><br>
    <span style="color:#68d391;"># エディタが開いた場合は :wq で保存終了</span><br>
    git merge featureB -m "featureBをmainに統合"  <span style="color:#68d391;"># エディタを開かない</span><br>
    <span style="color:#68d391;"># または</span><br>
    git merge featureB --no-edit  <span style="color:#68d391;"># デフォルトメッセージ使用</span><br>
    <br>
    <span style="color:#ffc107;"># ===== Phase 8: push(GitHubに送信) =====</span><br>
    <span style="color:#68d391;"># GitHubで新しいリポジトリを作成してから実行</span><br>
    git remote add origin https://github.com/ユーザー名/git-3min-practice.git<br>
    git push -u origin main<br>
    git push --all  <span style="color:#68d391;"># 全ブランチをpush</span><br>
    <br>
    <span style="color:#ffc107;"># ===== 最終確認 =====</span><br>
    git log --graph --oneline --all<br>
    git branch -a  <span style="color:#68d391;"># 全ブランチ確認</span><br>
    git status  <span style="color:#68d391;"># 状態確認</span>
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'mkdir git-3min-practice\ncd git-3min-practice\ngit init\necho \"# 3分Git実践\" > README.md\ngit add README.md\ngit commit -m \"Initial commit\"\ngit checkout -b featureA\necho \"機能A - パート1\" > featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート1を追加\"\necho \"機能A - パート2\" >> featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート2を追加\"\ngit checkout main\necho \"メイン作業 - その1\" > main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業1を追加\"\necho \"メイン作業 - その2\" >> main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業2を追加\"\ngit checkout -b featureB\necho \"機能B - 開始\" > featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 開始\"\necho \"機能B - 完了\" >> featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 完了\"\ngit log --graph --oneline --all\ngit checkout featureA\ngit rebase main\ngit checkout featureB\ngit revert HEAD --no-edit\ngit checkout main\ngit merge featureA\ngit merge featureB -m \"featureBをmainに統合\"\ngit log --graph --oneline --all')">コピー</button>
                    </div>
                </div>
            </div>
        </div>
    
        <script>
            function copyCommand(button, command) {
                navigator.clipboard.writeText(command).then(() => {
                    const originalText = button.textContent;
                    button.textContent = 'コピー完了!';
                    button.classList.add('copied');
                    
                    setTimeout(() => {
                        button.textContent = originalText;
                        button.classList.remove('copied');
                    }, 2000);
                });
            }
    
            function downloadExcel() {
                const wb = XLSX.utils.book_new();
    
                // シート1: 3分実践フロー
                const flowData = [
                    ['Phase', '時間', 'タスク', 'コマンド'],
                    ['0', '20秒', '準備: リポジトリ作成', 'mkdir git-3min-practice && cd git-3min-practice\ngit init\necho "# 3分Git実践" > README.md\ngit add README.md\ngit commit -m "Initial commit"'],
                    ['1', '40秒', 'featureAで2回コミット', 'git checkout -b featureA\necho "機能A - パート1" > featureA.txt\ngit add featureA.txt\ngit commit -m "featureA: パート1を追加"\necho "機能A - パート2" >> featureA.txt\ngit add featureA.txt\ngit commit -m "featureA: パート2を追加"'],
                    ['2', '20秒', 'mainで2回コミット', 'git checkout main\necho "メイン作業 - その1" > main-work.txt\ngit add main-work.txt\ngit commit -m "main: 作業1を追加"\necho "メイン作業 - その2" >> main-work.txt\ngit add main-work.txt\ngit commit -m "main: 作業2を追加"'],
                    ['3', '30秒', 'featureBで2回コミット', 'git checkout -b featureB\necho "機能B - 開始" > featureB.txt\ngit add featureB.txt\ngit commit -m "featureB: 開始"\necho "機能B - 完了" >> featureB.txt\ngit add featureB.txt\ngit commit -m "featureB: 完了"'],
                    ['4', '20秒', 'rebase: featureAを一直線に', 'git checkout featureA\ngit rebase main'],
                    ['5', '15秒', 'revert: コミット取り消し', 'git checkout featureB\ngit revert HEAD --no-edit'],
                    ['6', '20秒', 'merge: featureA統合', 'git checkout main\ngit merge featureA'],
                    ['7', '15秒', 'merge: featureB統合', 'git merge featureB -m "featureBをmainに統合"'],
                    ['8', '20秒', 'push: GitHubに送信', 'git remote add origin <URL>\ngit push -u origin main\ngit push --all']
                ];
                const ws1 = XLSX.utils.aoa_to_sheet(flowData);
                ws1['!cols'] = [{wch: 8}, {wch: 10}, {wch: 30}, {wch: 70}];
                XLSX.utils.book_append_sheet(wb, ws1, '3分実践フロー');
    
                // シート2: Viエディタ基本コマンド
                const viData = [
                    ['コマンド', '説明', '使用場面', '優先度'],
                    ['i', '編集モードに入る(Insert)', 'テキストを入力する前', '★★★★★'],
                    ['ESC', '編集モードを終了', '入力が終わった後', '★★★★★'],
                    [':wq', '保存して終了(Write & Quit)', '編集が完了した時', '★★★★★'],
                    [':x', '保存して終了(:wq と同じ)', '編集が完了した時', '★★★★☆'],
                    [':q!', '保存せずに終了(強制)', '変更を破棄したい時', '★★★★★'],
                    [':w', '保存(終了しない)', '途中で保存したい時', '★★★☆☆'],
                    ['dd', '1行削除', '不要な行を消す時', '★★★☆☆'],
                    ['u', '元に戻す(Undo)', '間違えた時', '★★★☆☆'],
                    ['yy', '1行コピー', '行をコピーしたい時', '★★☆☆☆'],
                    ['p', '貼り付け', 'コピーした内容を貼る時', '★★☆☆☆']
                ];
                const ws2 = XLSX.utils.aoa_to_sheet(viData);
                ws2['!cols'] = [{wch: 15}, {wch: 35}, {wch: 30}, {wch: 12}];
                XLSX.utils.book_append_sheet(wb, ws2, 'Viエディタコマンド');
    
                // シート3: マージコミットメッセージ対処法
                const mergeMessageData = [
                    ['方法', 'コマンド', '説明', 'おすすめ度'],
                    ['方法1: デフォルトメッセージ使用', ':wq', 'そのまま保存して終了', '★★★★★'],
                    ['方法2: メッセージ編集', 'i → [編集] → ESC → :wq', 'メッセージをカスタマイズ', '★★★★☆'],
                    ['方法3: キャンセル', ':q!', 'マージを中止', '★★★☆☆'],
                    ['予防1: コマンドでメッセージ指定', 'git merge branch -m "メッセージ"', 'エディタを開かない', '★★★★★'],
                    ['予防2: --no-editオプション', 'git merge branch --no-edit', 'デフォルトメッセージで即実行', '★★★★★'],
                    ['予防3: エディタ変更', 'git config --global core.editor "code --wait"', 'VS Codeなど使いやすいエディタに変更', '★★★★☆']
                ];
                const ws3 = XLSX.utils.aoa_to_sheet(mergeMessageData);
                ws3['!cols'] = [{wch: 25}, {wch: 45}, {wch: 35}, {wch: 12}];
                XLSX.utils.book_append_sheet(wb, ws3, 'マージメッセージ対処法');
    
                // シート4: コマンド比較(rebase/revert/merge)
                const compareData = [
                    ['操作', 'コマンド', '効果', '履歴への影響', '使用場面'],
                    ['rebase', 'git rebase main', 'ブランチのコミットを付け替える', '履歴が書き換わる(一直線)', '自分のブランチを最新化'],
                    ['revert', 'git revert HEAD', 'コミットを打ち消す新しいコミット作成', '履歴は残る(安全)', '公開済みコミットの取り消し'],
                    ['merge', 'git merge feature', 'ブランチを統合', 'マージコミットが作成される', 'ブランチをmainに統合'],
                    ['reset', 'git reset --hard HEAD^', 'コミットを削除', '履歴が消える(危険)', 'ローカルのみの取り消し']
                ];
                const ws4 = XLSX.utils.aoa_to_sheet(compareData);
                ws4['!cols'] = [{wch: 15}, {wch: 25}, {wch: 40}, {wch: 30}, {wch: 30}];
                XLSX.utils.book_append_sheet(wb, ws4, 'コマンド比較');
    
                // シート5: トラブルシューティング
                const troubleData = [
                    ['トラブル', '原因', '対処法', 'コマンド'],
                    ['エディタが開いて困った', 'mergeでメッセージ入力を求められた', ':wq で保存終了', ':wq'],
                    ['エ<!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>3分Git実践ガイド</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
        <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            body {
                font-family: 'Segoe UI', Meiryo, sans-serif;
                background: linear-gradient(135deg, #667eea  0%, #764ba2  100%);
                min-height: 100vh;
                padding: 20px;
            }
            .container {
                max-width: 1400px;
                margin: 0 auto;
                background: white;
                border-radius: 20px;
                box-shadow: 0 20px 60px rgba(0,0,0,0.3);
                overflow: hidden;
            }
            .header {
                background: linear-gradient(135deg, #ff6b6b  0%, #ee5a6f  100%);
                color: white;
                padding: 40px;
                text-align: center;
            }
            .header h1 {
                font-size: 2.5em;
                margin-bottom: 10px;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
            }
            .timer {
                background: white;
                color: #ff6b6b ;
                font-size: 3em;
                font-weight: bold;
                padding: 20px;
                border-radius: 15px;
                margin: 20px 40px;
                text-align: center;
                box-shadow: 0 4px 15px rgba(0,0,0,0.2);
            }
            .content {
                padding: 40px;
            }
            .phase {
                margin-bottom: 30px;
                border-left: 5px solid #667eea ;
                padding-left: 20px;
            }
            .phase-header {
                background: linear-gradient(135deg, #667eea  0%, #764ba2  100%);
                color: white;
                padding: 15px 25px;
                border-radius: 10px;
                margin: 20px 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .phase-timer {
                background: rgba(255,255,255,0.3);
                padding: 5px 15px;
                border-radius: 20px;
                font-size: 0.9em;
            }
            .command-container {
                position: relative;
                margin: 15px 0;
            }
            .command-box {
                background: #2d3748 ;
                color: #68d391 ;
                padding: 15px;
                border-radius: 8px;
                font-family: 'Courier New', monospace;
                font-size: 0.95em;
                overflow-x: auto;
                line-height: 1.8;
            }
            .copy-btn {
                position: absolute;
                top: 10px;
                right: 10px;
                background: #667eea ;
                color: white;
                border: none;
                padding: 8px 15px;
                border-radius: 5px;
                cursor: pointer;
                font-size: 0.9em;
                transition: all 0.3s;
                z-index: 10;
            }
            .copy-btn:hover {
                background: #5568d3 ;
            }
            .copy-btn.copied {
                background: #28a745 ;
            }
            .output-box {
                background: #1a202c ;
                color: #e2e8f0 ;
                padding: 15px;
                border-radius: 8px;
                font-family: 'Courier New', monospace;
                font-size: 0.9em;
                margin-top: 10px;
                overflow-x: auto;
                line-height: 1.6;
            }
            .visual {
                background: #f8f9fa ;
                padding: 20px;
                border-radius: 10px;
                margin: 15px 0;
                font-family: 'Courier New', monospace;
                font-size: 0.9em;
            }
            .note {
                background: #fff3cd ;
                border-left: 4px solid #ffc107 ;
                padding: 15px;
                margin: 15px 0;
                border-radius: 5px;
            }
            .success {
                background: #d4edda ;
                border-left: 4px solid #28a745 ;
                padding: 15px;
                margin: 15px 0;
                border-radius: 5px;
            }
            .warning {
                background: #ffe5e5 ;
                border-left: 4px solid #f44336 ;
                padding: 15px;
                margin: 15px 0;
                border-radius: 5px;
            }
            .highlight {
                background: #fff9c4 ;
                padding: 2px 6px;
                border-radius: 3px;
                font-weight: bold;
            }
            table {
                width: 100%;
                border-collapse: collapse;
                margin-top: 15px;
                background: white;
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                border-radius: 10px;
                overflow: hidden;
            }
            th {
                background: linear-gradient(135deg, #667eea  0%, #764ba2  100%);
                color: white;
                padding: 15px;
                text-align: left;
                font-weight: 600;
            }
            td {
                padding: 12px 15px;
                border-bottom: 1px solid #e9ecef ;
            }
            .download-section {
                padding: 30px 40px;
                background: #f8f9fa ;
                border-bottom: 3px solid #e9ecef ;
                text-align: center;
            }
            .btn-download {
                background: linear-gradient(135deg, #ff6b6b  0%, #ee5a6f  100%);
                color: white;
                border: none;
                padding: 15px 40px;
                font-size: 1.1em;
                border-radius: 50px;
                cursor: pointer;
                transition: all 0.3s;
                box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
            }
            .btn-download:hover {
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(255, 107, 107, 0.6);
            }
            .step-indicator {
                background: linear-gradient(135deg, #a8edea  0%, #fed6e3  100%);
                padding: 10px 20px;
                border-radius: 20px;
                display: inline-block;
                font-weight: bold;
                margin-bottom: 10px;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>⚡ 3分完結!Git実践マスター</h1>
                <p>2ブランチ切り替え → コミット → rebase/revert/merge/push</p>
            </div>
    
            <div class="timer">
                ⏱️ 3:00
            </div>
    
            <div class="download-section">
                <button class="btn-download" onclick="downloadExcel()">
                    📥 全コマンドをExcelでダウンロード
                </button>
            </div>
    
            <div class="content">
                <div class="note">
                    <h3 style="margin-bottom:10px;">🎯 この3分で学べること</h3>
                    <ul style="margin-left:20px;">
                        <li>✅ ブランチ切り替えの実践</li>
                        <li>✅ 複数コミットの作成</li>
                        <li>✅ rebase(履歴を一直線に)</li>
                        <li>✅ revert(コミットの取り消し)</li>
                        <li>✅ merge(ブランチ統合)</li>
                        <li>✅ push(GitHubへ送信)</li>
                    </ul>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 0:</strong> 準備(初回のみ)</span>
                        <span class="phase-timer">20秒</span>
                    </div>
    
                    <div class="step-indicator">Step 0-1: 練習用リポジトリ作成</div>
                    <div class="command-container">
                        <div class="command-box">
    # 練習用ディレクトリ作成<br>
    mkdir git-3min-practice<br>
    cd git-3min-practice<br>
    git init<br><br>
    # 最初のコミット<br>
    echo "# 3分Git実践" > README.md<br>
    git add README.md<br>
    git commit -m "Initial commit"
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'mkdir git-3min-practice\ncd git-3min-practice\ngit init\necho \"# 3分Git実践\" > README.md\ngit add README.md\ngit commit -m \"Initial commit\"')">コピー</button>
                    </div>
    
                    <div class="success">
                        <strong>✅ 準備完了!</strong> mainブランチに最初のコミットができました
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 1:</strong> featureAブランチで2回コミット</span>
                        <span class="phase-timer">40秒</span>
                    </div>
    
                    <div class="step-indicator">Step 1-1: featureAブランチ作成・切り替え</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout -b featureA
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout -b featureA')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 1-2: 1回目のコミット</div>
                    <div class="command-container">
                        <div class="command-box">
    echo "機能A - パート1" > featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート1を追加"
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'echo \"機能A - パート1\" > featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート1を追加\"')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 1-3: 2回目のコミット</div>
                    <div class="command-container">
                        <div class="command-box">
    echo "機能A - パート2" >> featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート2を追加"
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'echo \"機能A - パート2\" >> featureA.txt\ngit add featureA.txt\ngit commit -m \"featureA: パート2を追加\"')">コピー</button>
                    </div>
    
                    <div class="visual">
    <strong>現在の状態:</strong>
    * 2b5e846 (HEAD -> featureA) featureA: パート2を追加
    * 1a4c923 featureA: パート1を追加
    * c3d7a12 (main) Initial commit
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 2:</strong> mainブランチで作業</span>
                        <span class="phase-timer">20秒</span>
                    </div>
    
                    <div class="step-indicator">Step 2-1: mainブランチに切り替え</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout main
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout main')">コピー</button>
                    </div>
    
                    <div class="note">
                        <strong>💡 確認:</strong> featureA.txt が消えています!これが正常です。
                    </div>
    
                    <div class="step-indicator">Step 2-2: mainで2回コミット</div>
                    <div class="command-container">
                        <div class="command-box">
    # 1回目<br>
    echo "メイン作業 - その1" > main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業1を追加"<br><br>
    # 2回目<br>
    echo "メイン作業 - その2" >> main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業2を追加"
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'echo \"メイン作業 - その1\" > main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業1を追加\"\necho \"メイン作業 - その2\" >> main-work.txt\ngit add main-work.txt\ngit commit -m \"main: 作業2を追加\"')">コピー</button>
                    </div>
    
                    <div class="visual">
    <strong>現在の状態(分岐している):</strong>
    * 4d8f156 (HEAD -> main) main: 作業2を追加
    * 3c7e245 main: 作業1を追加
    | * 2b5e846 (featureA) featureA: パート2を追加
    | * 1a4c923 featureA: パート1を追加
    |/
    * c3d7a12 Initial commit
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 3:</strong> featureBブランチで作業</span>
                        <span class="phase-timer">30秒</span>
                    </div>
    
                    <div class="step-indicator">Step 3-1: featureBブランチ作成</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout -b featureB
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout -b featureB')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 3-2: featureBで2回コミット</div>
                    <div class="command-container">
                        <div class="command-box">
    # 1回目<br>
    echo "機能B - 開始" > featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 開始"<br><br>
    # 2回目<br>
    echo "機能B - 完了" >> featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 完了"
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'echo \"機能B - 開始\" > featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 開始\"\necho \"機能B - 完了\" >> featureB.txt\ngit add featureB.txt\ngit commit -m \"featureB: 完了\"')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 3-3: 全体の履歴を確認</div>
                    <div class="command-container">
                        <div class="command-box">
    git log --graph --oneline --all
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git log --graph --oneline --all')">コピー</button>
                    </div>
    
                    <div class="visual">
    <strong>現在の状態(3つのブランチ):</strong>
    * 6f9a234 (HEAD -> featureB) featureB: 完了
    * 5e8b123 featureB: 開始
    * 4d8f156 (main) main: 作業2を追加
    * 3c7e245 main: 作業1を追加
    | * 2b5e846 (featureA) featureA: パート2を追加
    | * 1a4c923 featureA: パート1を追加
    |/
    * c3d7a12 Initial commit
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 4:</strong> rebase(featureAを一直線に)</span>
                        <span class="phase-timer">20秒</span>
                    </div>
    
                    <div class="step-indicator">Step 4-1: featureAに切り替えてrebase</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout featureA<br>
    git rebase main
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout featureA\ngit rebase main')">コピー</button>
                    </div>
    
                    <div class="output-box">
    Successfully rebased and updated refs/heads/featureA.
                    </div>
    
                    <div class="visual">
    <strong>rebase後(featureAが一直線に):</strong>
    * 7g1b345 (HEAD -> featureA) featureA: パート2を追加
    * 6h2c456 featureA: パート1を追加
    | * 6f9a234 (featureB) featureB: 完了
    | * 5e8b123 featureB: 開始
    |/
    * 4d8f156 (main) main: 作業2を追加
    * 3c7e245 main: 作業1を追加
    * c3d7a12 Initial commit
                    </div>
    
                    <div class="note">
                        <strong>💡 rebase の効果:</strong> featureAのコミットがmainの最新の上に移動。一直線の履歴になりました!
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 5:</strong> revert(コミットの取り消し)</span>
                        <span class="phase-timer">15秒</span>
                    </div>
    
                    <div class="step-indicator">Step 5-1: featureBの最新コミットを取り消す</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout featureB<br>
    git revert HEAD --no-edit
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout featureB\ngit revert HEAD --no-edit')">コピー</button>
                    </div>
    
                    <div class="output-box">
    [featureB 8i3d567] Revert "featureB: 完了"
     1 file changed, 1 deletion(-)
                    </div>
    
                    <div class="visual">
    <strong>revert後(取り消しコミットが追加):</strong>
    * 8i3d567 (HEAD -> featureB) Revert "featureB: 完了"
    * 6f9a234 featureB: 完了
    * 5e8b123 featureB: 開始
    * 4d8f156 (main) main: 作業2を追加
    ...
                    </div>
    
                    <div class="warning">
                        <strong>⚠️ revert vs reset の違い:</strong>
                        <ul style="margin-left:20px; margin-top:10px;">
                            <li><strong>revert:</strong> 取り消しを新しいコミットとして記録(履歴が残る・安全)</li>
                            <li><strong>reset:</strong> コミット自体を削除(履歴が消える・危険)</li>
                        </ul>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 6:</strong> merge(featureAをmainに統合)</span>
                        <span class="phase-timer">20秒</span>
                    </div>
    
                    <div class="step-indicator">Step 6-1: mainに切り替えてmerge</div>
                    <div class="command-container">
                        <div class="command-box">
    git checkout main<br>
    git merge featureA
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git checkout main\ngit merge featureA')">コピー</button>
                    </div>
    
                    <div class="output-box">
    Updating 4d8f156..7g1b345
    Fast-forward
     featureA.txt | 2 ++
     1 file changed, 2 insertions(+)
     create mode 100644 featureA.txt
                    </div>
    
                    <div class="note">
                        <strong>💡 Fast-forward とは?</strong> rebaseしたので、一直線の履歴。単純に進めるだけでマージ完了!
                    </div>
    
                    <div class="visual">
    <strong>merge後(featureAの変更がmainに統合):</strong>
    * 7g1b345 (HEAD -> main, featureA) featureA: パート2を追加
    * 6h2c456 featureA: パート1を追加
    | * 8i3d567 (featureB) Revert "featureB: 完了"
    | * 6f9a234 featureB: 完了
    | * 5e8b123 featureB: 開始
    |/
    * 4d8f156 main: 作業2を追加
    * 3c7e245 main: 作業1を追加
    * c3d7a12 Initial commit
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 7:</strong> featureBもmerge(通常のマージ)</span>
                        <span class="phase-timer">15�span>
                    </div>
    
                    <div class="step-indicator">Step 7-1: featureBをmerge</div>
                    <div class="command-container">
                        <div class="command-box">
    git merge featureB
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git merge featureB')">コピー</button>
                    </div>
    
                    <div class="output-box">
    Merge made by the 'recursive' strategy.
     featureB.txt | 2 ++
     1 file changed, 2 insertions(+)
     create mode 100644 featureB.txt
                    </div>
    
                    <div class="visual">
    <strong>merge後(マージコミット作成):</strong>
    *   9j4e678 (HEAD -> main) Merge branch 'featureB'
    |\
    | * 8i3d567 (featureB) Revert "featureB: 完了"
    | * 6f9a234 featureB: 完了"
    | * 5e8b123 featureB: 開始
    * | 7g1b345 (featureA) featureA: パート2を追加
    * | 6h2c456 featureA: パート1を追加
    |/
    * 4d8f156 main: 作業2を追加
    * 3c7e245 main: 作業1を追加
    * c3d7a12 Initial commit
                    </div>
    
                    <div class="note">
                        <strong>💡 2種類のmerge:</strong>
                        <ul style="margin-left:20px; margin-top:10px;">
                            <li><strong>Fast-forward:</strong> rebase後のmerge。一直線</li>
                            <li><strong>Recursive:</strong> 通常のmerge。マージコミット作成</li>
                        </ul>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>Phase 8:</strong> push(GitHubに送信)</span>
                        <span class="phase-timer">20秒</span>
                    </div>
    
                    <div class="step-indicator">Step 8-1: GitHubリポジトリと接続(初回のみ)</div>
                    <div class="command-container">
                        <div class="command-box">
    # GitHubで新しいリポジトリを作成してから<br>
    git remote add origin https://github.com/あなたのユーザー名/git-3min-practice.git
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git remote add origin https://github.com/ユーザー名/git-3min-practice.git')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 8-2: mainブランチをpush</div>
                    <div class="command-container">
                        <div class="command-box">
    git push -u origin main
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git push -u origin main')">コピー</button>
                    </div>
    
                    <div class="step-indicator">Step 8-3: 全ブランチをpush</div>
                    <div class="command-container">
                        <div class="command-box">
    git push --all
                        </div>
                        <button class="copy-btn" onclick="copyCommand(this, 'git push --all')">コピー</button>
                    </div>
    
                    <div class="success">
                        <h3 style="margin-bottom:10px;">🎉 完了!</h3>
                        <ul style="margin-left:20px;">
                            <li>✅ 2つのブランチ(featureA, featureB)作成</li>
                            <li>✅ 各ブランチで2回以上コミット</li>
                            <li>✅ rebase でfeatureAを一直線に</li>
                            <li>✅ revert でfeatureBのコミットを取り消し</li>
                            <li>✅ merge で両ブランチをmainに統合</li>
                            <li>✅ push でGitHubに送信</li>
                        </ul>
                    </div>
                </div>
    
                <div class="phase">
                    <div class="phase-header">
                        <span><strong>おまけ:</strong> 全コマンドを一気にコピー</span>
                        <span class="phase-timer">0秒</span>
                    </div>
    
                    <div class="command-container">
                        <div class="command-box" style="max-height:400px; overflow-y:auto;">
    # Phase 0: 準備<br>
    mkdir git-3min-practice && cd git-3min-practice<br>
    git init<br>
    echo "# 3分Git実践" > README.md<br>
    git add README.md<br>
    git commit -m "Initial commit"<br><br>
    # Phase 1: featureAブランチ<br>
    git checkout -b featureA<br>
    echo "機能A - パート1" > featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート1を追加"<br>
    echo "機能A - パート2" >> featureA.txt<br>
    git add featureA.txt<br>
    git commit -m "featureA: パート2を追加"<br><br>
    # Phase 2: mainブランチ<br>
    git checkout main<br>
    echo "メイン作業 - その1" > main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業1を追加"<br>
    echo "メイン作業 - その2" >> main-work.txt<br>
    git add main-work.txt<br>
    git commit -m "main: 作業2を追加"<br><br>
    # Phase 3: featureBブランチ<br>
    git checkout -b featureB<br>
    echo "機能B - 開始" > featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 開始"<br>
    echo "機能B - 完了" >> featureB.txt<br>
    git add featureB.txt<br>
    git commit -m "featureB: 完了"<br><br>
    # Phase 4: rebase<br>
    git checkout featureA<br>
    git rebase main<br><br>
    # Phase 5: revert<br>
    git checkout featureB<br>
    git revert HEAD --no-edit<br><br>
    # Phase 6-7: merge<br>
    git checkout main<br>
    git merge featureA<br>
    git merge featureB<br><br>
    # Phase 8: push(GitHubリポジトリ作成後

    あなたへのおすすめ