<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Merge on kenji.blog</title><link>http://kenji.blog/tags/merge/</link><description>Recent content in Merge on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ja</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 09:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/tags/merge/index.xml" rel="self" type="application/rss+xml"/><item><title>【Gitコマンド】rebaseとmergeの違いと、実務での正しい使い分け</title><link>http://kenji.blog/p/git-rebase-vs-merge-practical-guide/</link><pubDate>Sun, 13 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/p/git-rebase-vs-merge-practical-guide/</guid><description>&lt;img src="http://kenji.blog/p/git-rebase-vs-merge-practical-guide/img/eyecatch.jpg" alt="Featured image of post 【Gitコマンド】rebaseとmergeの違いと、実務での正しい使い分け" />&lt;h1 id="1-はじめになぜmergeかrebaseかは永遠の課題なのか">1. はじめに：なぜ「mergeかrebaseか」は永遠の課題なのか
&lt;/h1>&lt;p>Gitは現代のソフトウェア開発において不可欠なバージョン管理システムです。複数人の開発者が同時にコードベースを変更する際、Gitの強力なブランチモデルが威力を発揮します。しかし、チーム開発において「&lt;code>merge&lt;/code> と &lt;code>rebase&lt;/code> のどちらを使うべきか」という議論は、初心者から熟練者まで常に開発者を悩ませるトピックの一つです。&lt;/p>
&lt;p>この記事では、Gitの内部構造であるDAG（有向非巡回グラフ）やコミットハッシュの数学的性質から紐解き、&lt;code>git merge&lt;/code> と &lt;code>git rebase&lt;/code> のメカニズムの違いを深く掘り下げます。そして、実務においてどのようにこれらを使い分けるべきか、具体的なワークフローを交えて徹底的に解説します。単なるコマンドの紹介にとどまらず、裏側でGitがどのような計算を行っているのかまで理解することで、コンフリクトへの恐怖をなくし、クリーンで追跡可能な履歴を構築できるようになります。&lt;/p>
&lt;hr>
&lt;h1 id="2-gitの内部構造コミットハッシュとオブジェクトモデル">2. Gitの内部構造：コミットハッシュとオブジェクトモデル
&lt;/h1>&lt;p>Gitが履歴をどのように統合するかを理解するためには、まずGitがデータをどのように保存しているかを知る必要があります。Gitは単なるファイル変更の差分（パッチ）を保存しているわけではなく、ある時点のファイルシステム全体のスナップショットを保存しています。&lt;/p>
&lt;h2 id="21-コミットハッシュの暗号学的性質">2.1 コミットハッシュの暗号学的性質
&lt;/h2>&lt;p>Gitの各コミットは、その内容を元に計算されたSHA-1（Secure Hash Algorithm 1）ハッシュ関数による40桁の16進数で一意に識別されます。コミットオブジェクトは以下の要素から構成されます：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Treeオブジェクトへのポインタ&lt;/strong>: その時点のディレクトリ構造とファイル（Blob）のスナップショット&lt;/li>
&lt;li>&lt;strong>親コミットへのポインタ&lt;/strong>: 1つ以上の親コミットのハッシュ値（初回コミットは親を持たず、マージコミットは2つ以上の親を持ちます）&lt;/li>
&lt;li>&lt;strong>作成者情報（Author）&lt;/strong>: コードを書いた人と日時&lt;/li>
&lt;li>&lt;strong>コミッター情報（Committer）&lt;/strong>: コミットを作成・適用した人と日時&lt;/li>
&lt;li>&lt;strong>コミットメッセージ&lt;/strong>: 変更の意図を説明するテキスト&lt;/li>
&lt;/ol>
&lt;p>数学的に表現すると、コミットオブジェクト $C$ に対するハッシュ値 $H(C)$ は次のように定義されます：&lt;/p>
$$
H(C) = \text{SHA-1}( \text{tree} \parallel \text{parent} \parallel \text{author} \parallel \text{committer} \parallel \text{message} )
$$&lt;p>ここで、$\parallel$ はデータの結合を表します。ハッシュ関数の特性により、コミットメッセージを1文字変えただけでも、あるいは親コミットが異なるだけでも、全く異なるハッシュ値が生成されます。つまり、&lt;strong>コミットは不変（Immutable）&lt;/strong> です。後述する &lt;code>rebase&lt;/code> が「履歴を書き換える」と表現されるのは、実際には「内容が似ているが異なるハッシュ値を持つ新しいコミットを作成している」ためです。&lt;/p>
&lt;p>ハッシュ空間の大きさは $2^{160}$ であり、衝突（異なるコミットが同じハッシュ値を持つこと）が発生する確率 $P$ は、誕生日攻撃（Birthday Paradox）の理論を用いると次のように近似できます（$n$ はコミット数）：&lt;/p>
$$
P(\text{collision}) \approx 1 - \exp\left(-\frac{n^2}{2 \times 2^{160}}\right)
$$&lt;p>この確率は極めて低く、実用上Gitのコミットハッシュが衝突することはほぼあり得ません。&lt;/p>
&lt;hr>
&lt;h1 id="3-グラフ理論とdaggit履歴の数学的モデル">3. グラフ理論とDAG：Git履歴の数学的モデル
&lt;/h1>&lt;p>Gitのコミット履歴は、グラフ理論における「有向非巡回グラフ（Directed Acyclic Graph, DAG）」としてモデル化されます。&lt;/p>
&lt;h2 id="31-dag有向非巡回グラフとは">3.1 DAG（有向非巡回グラフ）とは
&lt;/h2>&lt;p>グラフ $G = (V, E)$ において、$V$ はコミットの集合（頂点）、$E$ はコミット間の親子関係を示す有向エッジの集合です。Gitにおいては、エッジの向きは「子コミットから親コミット」へと向かいます。新しいコミットは過去のコミットへのポインタを保持しているためです。&lt;/p>
&lt;pre class="mermaid">
graph BT
A[&amp;#34;Commit A (Initial)&amp;#34;]
B[&amp;#34;Commit B&amp;#34;]
C[&amp;#34;Commit C (Main)&amp;#34;]
D[&amp;#34;Commit D (Feature)&amp;#34;]
E[&amp;#34;Commit E (Merge)&amp;#34;]
B --&amp;gt; A
C --&amp;gt; B
D --&amp;gt; B
E --&amp;gt; C
E --&amp;gt; D
&lt;/pre>
&lt;p>DAGの最大の特徴は「サイクル（循環）が存在しない」ことです。これにより、コミット履歴を遡るアルゴリズムは無限ループに陥ることがなく、確実に終端（初期コミット）に到達できます。&lt;/p>
&lt;h2 id="32-トポロジカルソートと履歴の順序">3.2 トポロジカルソートと履歴の順序
&lt;/h2>&lt;p>Gitの &lt;code>git log&lt;/code> コマンドなどで履歴を表示する際、DAGはトポロジカルソート（Topological Sort）アルゴリズムによって1次元のリストとして順序付けされます。DAGにおける任意の有向エッジ $u \to v$ （$u$ は $v$ の子）について、リスト内で $u$ が $v$ よりも前に来るように並べ替えます。&lt;/p>
&lt;hr>
&lt;h1 id="4-git-merge-のメカニズムと種類">4. git merge のメカニズムと種類
&lt;/h1>&lt;p>ブランチの変更を統合する最も基本的なコマンドが &lt;code>git merge&lt;/code> です。しかし、現在の状態に応じてGitは異なるマージ戦略を自動的に選択します。&lt;/p>
&lt;h2 id="41-fast-forward-マージ--ff">4.1 Fast-Forward マージ（&amp;ndash;ff）
&lt;/h2>&lt;p>統合先（例：&lt;code>main&lt;/code>）のブランチが、統合元（例：&lt;code>feature&lt;/code>）のブランチの直接の祖先である場合、Gitは「Fast-Forward（早送り）」マージを実行します。これは、新しいコミットを作成せず、単にブランチのポインタを前に進めるだけの操作です。&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
merge feature
&lt;/pre>
&lt;p>Fast-Forwardマージは履歴を一直線に保ちますが、「どのコミット群が一つの機能開発（feature）としてまとまっていたのか」というコンテキストが失われる欠点があります。&lt;/p>
&lt;h2 id="42-non-fast-forward-マージ--no-ff">4.2 Non-Fast-Forward マージ（&amp;ndash;no-ff）
&lt;/h2>&lt;p>&lt;code>git merge --no-ff&lt;/code> を明示的に指定すると、たとえFast-Forward可能な状況であっても、必ず新しい「マージコミット」を作成します。マージコミットは2つの親を持つ特別なコミットです。&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
commit id: &amp;#34;Main Work 1&amp;#34;
merge feature type: NORMAL
&lt;/pre>
&lt;p>この方法の利点は、機能ブランチの存在と歴史がDAG上に明確に残ることです。問題が発生した際、&lt;code>git revert -m 1 &amp;lt;マージコミットのハッシュ&amp;gt;&lt;/code> を実行することで、機能全体を一度に安全に取り消す（リバートする）ことが可能です。&lt;/p>
&lt;h2 id="43-3ウェイマージ3-way-mergeアルゴリズム">4.3 3ウェイマージ（3-Way Merge）アルゴリズム
&lt;/h2>&lt;p>統合先と統合元のブランチがそれぞれ独自のコミットを持っている場合、Gitは3ウェイマージを実行します。この際、GitはDAGを探索し、2つのブランチの「共通の祖先（Lowest Common Ancestor, LCA）」を見つけ出します。&lt;/p>
&lt;p>LCAを見つけるためのアルゴリズムの計算量 $T_{\text{LCA}}$ は、頂点数 $|V|$ とエッジ数 $|E|$ に対して線形時間で実行可能です：&lt;/p>
$$
T_{\text{LCA}} = \mathcal{O}(|V| + |E|)
$$&lt;p>Gitは「LCAの状態」「現在のブランチの状態」「相手のブランチの状態」の3つを比較し、変更が衝突していなければ自動的にマージコミットを生成します。&lt;/p>
&lt;hr>
&lt;h1 id="5-git-rebase-のメカニズムと履歴の再構築">5. git rebase のメカニズムと履歴の再構築
&lt;/h1>&lt;p>&lt;code>git merge&lt;/code> が履歴を「統合」するのに対し、&lt;code>git rebase&lt;/code> は履歴を「再構築（付け替え）」します。&lt;/p>
&lt;h2 id="51-rebaseの背後にある動き">5.1 Rebaseの背後にある動き
&lt;/h2>&lt;p>&lt;code>feature&lt;/code> ブランチを &lt;code>main&lt;/code> ブランチにリベースする（&lt;code>git rebase main&lt;/code>）際の内部動作は以下の通りです：&lt;/p>
&lt;ol>
&lt;li>&lt;code>feature&lt;/code> ブランチと &lt;code>main&lt;/code> ブランチの共通祖先（LCA）を見つける。&lt;/li>
&lt;li>LCAから &lt;code>feature&lt;/code> ブランチの先端までのコミットの差分を一時領域に保存する。&lt;/li>
&lt;li>&lt;code>feature&lt;/code> ブランチのポインタを &lt;code>main&lt;/code> ブランチの先端に移動させる。&lt;/li>
&lt;li>保存しておいた差分を、新しいベース（&lt;code>main&lt;/code>の先端）の上へ1つずつ順に適用（Cherry-Pick）し、新しいコミットを生成する。&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Commit A&amp;#34;] --&amp;gt; B[&amp;#34;Commit B&amp;#34;]
B --&amp;gt; C[&amp;#34;Commit C (Main)&amp;#34;]
B --&amp;gt; D[&amp;#34;Commit D (Old Feature)&amp;#34;]
D -.-&amp;gt; E[&amp;#34;Commit D&amp;#39; (New Feature)&amp;#34;]
C --&amp;gt; E
style D stroke-dasharray: 5 5, fill: #f9f9f9, color: #999
&lt;/pre>
&lt;p>ここで重要なのは、リベースによって生成されたコミット $D'$ は、元のコミット $D$ とは&lt;strong>親コミットが異なるため、全く異なるハッシュ値を持つ&lt;/strong>ということです（前述のハッシュ関数の定義 $H(C)$ を参照）。&lt;/p>
&lt;h2 id="52-インタラクティブリベースinteractive-rebase">5.2 インタラクティブリベース（Interactive Rebase）
&lt;/h2>&lt;p>&lt;code>git rebase -i&lt;/code>（または &lt;code>--interactive&lt;/code>）を使用すると、コミット履歴を思いのままに操作できます。これはローカルの履歴を整理するための最強のツールです。&lt;/p>
&lt;ul>
&lt;li>&lt;code>pick&lt;/code> : コミットをそのまま採用する&lt;/li>
&lt;li>&lt;code>reword&lt;/code> : コミットメッセージのみを修正する&lt;/li>
&lt;li>&lt;code>edit&lt;/code> : コミットの内容を修正するために一時停止する&lt;/li>
&lt;li>&lt;code>squash&lt;/code> : このコミットを前のコミットに融合し、メッセージも結合する&lt;/li>
&lt;li>&lt;code>fixup&lt;/code> : &lt;code>squash&lt;/code> と同じだが、このコミットのメッセージは破棄する&lt;/li>
&lt;li>&lt;code>drop&lt;/code> : コミットを完全に削除する&lt;/li>
&lt;/ul>
&lt;p>数学的に見れば、あるブランチに $N$ 個のコミットがある場合、リベースの順序入れ替えによって生成可能な線形履歴のバリエーション（順列） $P$ は以下のようになります。&lt;/p>
$$
P = N!
$$&lt;p>Gitは開発者に $N!$ 通りの自由を与え、履歴を論理的で美しい状態に保つことを可能にしています。&lt;/p>
&lt;hr>
&lt;h1 id="6-リベースの黄金則the-golden-rule-of-rebase">6. リベースの黄金則（The Golden Rule of Rebase）
&lt;/h1>&lt;p>&lt;code>rebase&lt;/code> は非常に強力ですが、一つの絶対的なルールが存在します。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>「公開されたパブリックな履歴に対して絶対にリベースを行ってはならない」&lt;/strong>
&lt;em>(Never rebase public history)&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;h2 id="61-なぜパブリックな履歴をリベースしてはいけないのか">6.1 なぜパブリックな履歴をリベースしてはいけないのか？
&lt;/h2>&lt;p>Gitは分散型です。あなたが &lt;code>origin/main&lt;/code> にプッシュしたコミットは、他の開発者のローカルリポジトリにもクローン（複製）されています。もしあなたが既にプッシュ済みのコミットをリベースして履歴を書き換え、&lt;code>git push --force&lt;/code> で強制上書きした場合、何が起きるでしょうか？&lt;/p>
&lt;p>他の開発者のローカルにあるDAGと、リモートのDAGが根本的に分岐してしまいます。他の開発者が &lt;code>git pull&lt;/code> を実行すると、Gitは異なる歴史を持つコミット群を無理やりマージしようとし、大量のコンフリクトや重複コミット（同じ変更内容だがハッシュが異なるコミット）が発生し、リポジトリがパニック状態に陥ります。&lt;/p>
&lt;p>リベースは**「まだ誰とも共有していない、ローカルのブランチ」**に対してのみ行うのが鉄則です。&lt;/p>
&lt;hr>
&lt;h1 id="7-コンフリクト競合の解決と-git-rebase---continue">7. コンフリクト（競合）の解決と git rebase &amp;ndash;continue
&lt;/h1>&lt;p>複数人が同じファイルの同じ箇所を変更した場合、コンフリクトが発生します。&lt;code>merge&lt;/code> と &lt;code>rebase&lt;/code> ではコンフリクトの解決プロセスが異なります。&lt;/p>
&lt;h2 id="71-mergeにおけるコンフリクト解決">7.1 Mergeにおけるコンフリクト解決
&lt;/h2>&lt;p>&lt;code>git merge&lt;/code> の場合、コンフリクトの解決は&lt;strong>1回だけ&lt;/strong>発生します。最終的なマージコミットを作成する直前に、すべての競合箇所を一度に修正します。&lt;/p>
&lt;h2 id="72-rebaseにおけるコンフリクト解決">7.2 Rebaseにおけるコンフリクト解決
&lt;/h2>&lt;p>&lt;code>git rebase&lt;/code> の場合、コミットを1つずつ再適用していく性質上、&lt;strong>各コミットごとにコンフリクトが発生する可能性&lt;/strong>があります。&lt;/p>
&lt;p>リベース中にコンフリクトが発生すると、Gitは処理を一時停止します。解決の流れは以下の通りです：&lt;/p>
&lt;ol>
&lt;li>エディタやIDE（VS Codeなど）を開き、コンフリクトマーカー（&lt;code>&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code> や &lt;code>======&lt;/code>、&lt;code>&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code>）を手動で修正する。&lt;/li>
&lt;li>修正したファイルをインデックスに追加する：
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add &amp;lt;修正したファイル&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>コミットは作成せず、リベース処理を再開する：
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>もしリベース自体を取りやめて元の状態に戻したい場合は、以下のコマンドを実行します：&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --abort
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>（※コンフリクトの解決が不要で、そのコミットごとスキップしたい場合は &lt;code>git rebase --skip&lt;/code> を使用します）&lt;/p>
&lt;hr>
&lt;h1 id="8-実務での正しい使い分けワークフロー実践">8. 実務での正しい使い分け（ワークフロー実践）
&lt;/h1>&lt;p>では、実際の開発現場では &lt;code>merge&lt;/code> と &lt;code>rebase&lt;/code> をどのように使い分けるべきでしょうか。ここでは最もスタンダードで安全なアプローチを紹介します。&lt;/p>
&lt;h2 id="81-シナリオ1ローカルでの作業履歴の整理rebaseの利用">8.1 【シナリオ1】ローカルでの作業履歴の整理（Rebaseの利用）
&lt;/h2>&lt;p>機能ブランチで開発中、細かなコミット（「タイポ修正」「一時保存」など）がたくさん積み重なってしまったとします。プルリクエスト（PR）を出す前に、これらを意味のある単位に整理するためにインタラクティブリベースを使用します。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># featureブランチにいる状態で実行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># （エディタが開き、squashやfixupを使って履歴を綺麗にする）&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>これにより、レビュアーにとって意図が伝わりやすい、美しいコミット履歴を作ることができます。&lt;/p>
&lt;h2 id="82-シナリオ2最新のmainブランチへの追従rebaseの利用">8.2 【シナリオ2】最新のmainブランチへの追従（Rebaseの利用）
&lt;/h2>&lt;p>開発が長引き、&lt;code>main&lt;/code> ブランチに他の人の変更がどんどんマージされていく場合、自分の &lt;code>feature&lt;/code> ブランチが古くなってしまいます。この場合、&lt;code>feature&lt;/code> ブランチを最新の &lt;code>main&lt;/code> にリベースして追従します。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># mainの最新情報を取得&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># featureブランチを最新のmainの上に付け替える&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase origin/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>これにより、履歴が一直線になり、後続のマージ時のコンフリクトを防ぐことができます。また、余計なマージコミット（&amp;ldquo;Merge branch &amp;lsquo;main&amp;rsquo; into feature&amp;rdquo;）が生成されるのを防ぐことができます。&lt;/p>
&lt;h2 id="83-シナリオ3完成した機能の統合mergeの利用">8.3 【シナリオ3】完成した機能の統合（Mergeの利用）
&lt;/h2>&lt;p>&lt;code>feature&lt;/code> ブランチでの開発が完了し、いよいよ &lt;code>main&lt;/code> ブランチに統合するフェーズです。ここでは &lt;strong>&lt;code>git merge --no-ff&lt;/code>&lt;/strong> を使用します（GitHubなどのPull Requestで「Create a merge commit」を選ぶのと同じです）。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge --no-ff feature -m &lt;span class="s2">&amp;#34;Merge feature: ユーザーログイン機能の実装&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>これにより、&lt;code>main&lt;/code> ブランチのDAG上に「ここで一つの機能がマージされた」という歴史の結節点（マージコミット）が残ります。後から履歴を見たときに、機能単位でコードを追いやすくなります。&lt;/p>
&lt;hr>
&lt;h1 id="9-結論まとめ">9. 結論（まとめ）
&lt;/h1>&lt;p>Gitの操作において「すべてをMergeで済ませる」または「すべてをRebaseで一直線にする」といった極端なアプローチは、それぞれ長所と短所があります。&lt;/p>
&lt;p>実務におけるベストプラクティスは、**「ローカルのプライベートな履歴は rebase で美しく整理し、パブリックな統合履歴は merge &amp;ndash;no-ff で文脈を残す」**というハイブリッドなアプローチです。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ローカル（個人の作業スペース）&lt;/strong>: &lt;code>rebase&lt;/code> を使って、無駄なコミットを排除し、最新のメインラインに追従して一直線の履歴を維持する。&lt;/li>
&lt;li>&lt;strong>グローバル（共有の作業スペース）&lt;/strong>: &lt;code>merge --no-ff&lt;/code> を使って、機能ブランチの存在をマージコミットとしてDAGに記録し、リバートやトラッキングを容易にする。&lt;/li>
&lt;/ul>
&lt;p>DAGの構造やハッシュ関数の仕組みといった数学的・アーキテクチャ的な背景を理解することで、Gitコマンドは単なる暗記から「意図を持った履歴の設計」へと昇華します。リベースの黄金則を守りながら、状況に応じた最適なコマンドを選択し、チーム全体にとって読みやすく保守しやすいクリーンなコミット履歴を構築していきましょう。&lt;/p></description></item></channel></rss>