「Gitの基礎 - rebaseとmergeの使い分け」の版間の差分

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

編集の要約なし
 
(同じ利用者による、間の2版が非表示)
92行目: 92行目:


== mergeを使用して統合する ==
== mergeを使用して統合する ==
topicブランチで機能を開発する間に、他のチームメンバによってmasterブランチがいつくか先に進んでいるとする。<br>
下図のように、topicブランチで開発する間において、masterブランチのコミットが先に進んでいるとする。<br>
このまま、materブランチにtopicブランチをmergeすると、コンフリクト(競合、衝突)が発生する。<br>
この時、materブランチにtopicブランチをmergeすると、コンフリクト (競合、衝突) が発生する。<br>
[[ファイル:Git Merge Rebase 1.png|フレームなし|中央]]
<br>
<br>
masterブランチ上でコンフリクトを解決するのは好ましくない。なぜなら、解決の結果が正常に動作するかどうか実証する必要があるからである。<br>
しかし、masterブランチ上でコンフリクトを解決するのは好ましくない。<br>
そこで、コンフリクトの解決の実証をローカルのtopicブランチで行うため、masterブランチ側の変更をtopicブランチに取り込む。<br>
これは、解決の結果が正常に動作するかどうか実証する必要があるからである。<br>
(ここで、コンフリクトを解決したものとする)<br>
<br>
<br>
次に、このtopicブランチの変更をmasterブランチに取り込む。(masterブランチをチェックアウトする)<br>
そこで、まず、コンフリクトの解決の実証をローカルのtopicブランチで行うため、masterブランチ側の変更をtopicブランチにmergeする。<br>
そして、topicブランチをmergeする。(この場合、--no-ffオプションを付加しない限りは、fast forward mergeになる)<br>
topicブランチに取り込むことにより、コンフリクトを解決する。<br>
これで、topicブランチのコミットと完全に同一のコミット(sha-1が同じ)が、masterブランチのコミットとして記録される。<br>
<br>
<br>
ここでは、masterブランチへの最終mergeを自分で行ったが、チーム開発に於いては、masterブランチの管理者に対してプルリクエストを送る場合もある。<br>
次に、masterブランチをチェックアウトして、topicブランチの変更をmasterブランチにmergeする。<br>
この時、--no-ffオプションを付加しない限りは、fast forward mergeとなる。<br>
<br>
これにより、topicブランチのコミットと完全に同一のコミット (sha-1が同じ) が、masterブランチのコミットとして記録される。<br>
<br>
チーム開発の場合、masterブランチへの最終マージにおいては、masterブランチの管理者に対してプルリクエストを送信して実施してもらう場合もある。<br>
<br><br>
<br><br>


109行目: 113行目:
rebaseは、再度(re)起点を定める(base)という意味合いがある。<br>
rebaseは、再度(re)起点を定める(base)という意味合いがある。<br>
<br>
<br>
まず、統合前の状態では上記と同様に、masterブランチとtopicブランチの間にコンフリクトが発生することが分かっているので、<br>
下図に、最初の状態 (rebase前) を示す。<br>
それを避けるため、topicブランチの起点を、masterブランチの最新のコミットで置き換える。<br>
mainブランチとtopicブランチが分岐しており、両ブランチで並行開発が行われているものとする。<br>
[[ファイル:Git Merge Rebase 2.png|フレームなし|中央]]
<center>図. rebase前の状態</center><br>
<br>
まず、統合前の状態では、masterブランチとtopicブランチの間にコンフリクトが発生する。<br>
それを避けるため、topicブランチの起点をmasterブランチの最新のコミットで置き換える。<br>
<br>
<br>
コンフリクトがあれば個別に解決する必要がある。rebaseでは、topicブランチのコミットを1つずつ順番にmasterブランチの最新の先端に付け加える処理が発生する。<br>
コンフリクトがあれば個別に解決する必要がある。<br>
例えば、topicブランチ上で、masterブランチとコンフリクトが発生するファイルを何度も繰り返し変更している場合は、その都度、競合が発生する可能性がある。<br>
<u>rebaseでは、topicブランチのコミットを1つずつ順番にmasterブランチの最新の先端に付け加える処理が発生する。</u><br>
そのため、コミットの多いtopicブランチをrebaseする場合は、作業が煩雑になる。(事前に、topicブランチの履歴をrebase -i等を使用して簡略化すると緩和できる)<br>
<br>
例えば、topicブランチ上において、masterブランチとコンフリクトが発生するファイルを何度も繰り返し変更している場合は、その都度、競合が発生する。<br>
そのため、コミットの多いtopicブランチをrebaseする場合は作業が煩雑になる。<br>
事前に、topicブランチの履歴を<code>rebase -i</code>コマンド等を実行して簡略化すると緩和できる。<br>
<br>
# topicブランチの起点が、mainブランチの最新コミットに移動する。
# topicブランチのコミットが順次適用されて、新しいコミット (3'、6'、8') として再作成される。<br>この過程でコンフリクトが発生する可能性があり、その都度解決が必要となる。
[[ファイル:Git Merge Rebase 3.png|フレームなし|中央]]
<center>図. rebase後の状態 (topicブランチの起点が移動)</center><br>
<br>
<br>
ここでは、rebaseした後のコンフリクトの解決と実証が正常に終了したものとする。<br>
ここでは、rebaseした後のコンフリクトの解決と実証が正常に終了したものとする。<br>
<br>
<br>
次に、この変更をmasterブランチに取り込む。<br>
次に、この変更をmasterブランチに取り込む。<br>
masterブランチをチェックアウトして、git merge --no-ff topic-branchコマンドを使用する。(<u>'''必ず、--no-ffオプションを付加すること'''</u>)<br>
masterブランチにチェックアウトして、<code>git merge --no-ff <ブランチ名  例: topic></code>コマンドを使用する。<br>
この時、topicブランチのコミットログがmasterブランチ側に残らない用に配慮する。(--no-ffオプションにより、fast forwardを行わない独立したコミットが作成される)<br>
<u>必ず、<code>--no-ff</code>オプションを付加すること。</u><br>
<br>
この時、topicブランチのコミットログがmasterブランチ側に残らないように配慮する必要がある。<br>
<code>--no-ff</code>オプションにより、fast forwardを行わない独立したコミットが作成される。<br>
<br>
masterブランチのコミットログを見ると、基本的には直列の履歴かつ変更コミットが機能ごと (topicブランチごと) に独立して見える。<br>
<br>
# --no-ffオプションにより、マージコミットが明示的に作成される。
# topicブランチの変更が1つのまとまりとしてmainブランチに統合される。
# mainブランチの履歴が直線的に保たれる。
[[ファイル:Git Merge Rebase 4.png|フレームなし|中央]]
<center>図. 最終的なmerge (--no-ff) 後の状態</center><br>
<br><br>
 
== rebase時のコンフリクトが発生する条件 ==
下図において、コンフリクトが発生する条件は、<br>
topicブランチのコミット (3', 6', 8') が、mainブランチの新しいコミット (4, 5, 7) と「同じファイルの同じ部分」を変更している場合のみである。<br>
<br>
[[ファイル:Git Merge Rebase 5.png|フレームなし|中央]]
<br>
# コミット3'のrebase時
#* masterブランチの4では、別ファイル(file_b.txt)の変更なのでコンフリクト無し。
#* masterブランチの5において、同じファイル (a.txt) を変更しているためコンフリクトが発生。
#: <br>
# コミット6'のrebase時
#* これもa.txtファイルの変更であるため、masterブランチの変更とコンフリクト発生の可能性がある。
#: <br>
# コミット8'のrebase時
#* masterブランチの7は、別ファイル (c.txt) の変更であるためコンフリクト無し。
#* ただし、masterブランチの4で変更されたb.txtファイルとコンフリクト発生の可能性がある。
<br>
したがって、<br>
* 異なるファイルの変更
*: コンフリクトは発生しない。
* 同じファイルでも異なる箇所の変更
*: コンフリクトは発生しない。
* 同じファイルの同じ箇所を変更
*: コンフリクトが発生する。
<br>
<br>
masterブランチのコミットログを見ると、基本的には直列の履歴かつ変更コミットが機能ごと(トピックブランチごと)に独立して見える。<br>
このため、rebaseの作業量は以下に示す要因によって大きく変わる。<br>
* 変更ファイルの重複度
* 変更箇所の重複度
* topicブランチのコミット数
<br><br>
<br><br>