Git mergeとrebaseの違い:例と使い分け

  1. ホーム
  2. ブログ
  3. ソフトウェア開発
ソフトウェア開発

Git mergeとrebaseの違い:例と使い分け

Gitのmergeとrebaseの選択で、プロジェクト履歴の見た目が決まります。同じ例と実際のログ出力で両者を比べ、失敗を防ぐ1つのルールを学び、安全なチームワークフローをそのまま使いましょう。

読了目安 7分
Git mergeとrebaseの違い:例と使い分け
ポイント
  • mergeは新しいマージコミットで2つのブランチをつなぎ、履歴をありのまま残します。
  • rebaseは自分のコミットを別のブランチの先頭に再適用し、一直線の履歴になりますが、コミットのハッシュは変わります。
  • 他の人がすでに取得したコミットをrebaseしてはいけません。
  • プルリクエストを出す前に自分のフィーチャーブランチをrebaseし、メインブランチに取り込むときはmergeを使いましょう。

フィーチャーブランチが main より遅れていて、新しい変更が必要です。Git mergeとrebaseは、それを取り込む2つの方法の選択で、どちらも正しい方法です。違いは、その後の履歴の見た目にあります。

小さなリポジトリを作って両方のコマンドを実行し、実際の出力を下に貼りました。想像ではなく結果を比べられます。Gitが初めての方は、まず初心者向けGitチュートリアル(英語)をご覧ください。

git mergeとgit rebaseの役割

git merge は2つのブランチの先頭を取り、1つにまとめます。両方に新しいコミットがある場合、Gitは親が2つのマージコミットを作ります。すでにあるものは何も変更されません。

git rebase は自分のブランチだけにあるコミットをいったん脇に置き、ブランチを相手の先頭に移動してから、コミットを1つずつ再適用します。再適用されたコミットは、変更内容は同じでも新しいハッシュを持つ新しいコミットです。

git mergeの実践

出発点は次のとおりです。main にコミットA、feature に2つのコミット(F1、F2)があり、その後 main にもう1つのコミット(M1)が追加されました。ここで main を feature にマージします。

git switch feature
git merge main
git log --oneline --graph

*   f507aab Merge main into feature
|\
| * 8842fb5 M1
* | 082cc6a F2
* | 5a71e3c F1
|/
* 8766865 A

グラフは実際の経緯を示しています。2本の作業ラインが合流しました。元のコミットF1とF2はハッシュを保ちます。代償はマージコミットが1つ増えることで、活発なプロジェクトではグラフが網の目のようになります。

git rebaseの実践

出発点は同じですが、今度は feature を main の上にrebaseします。

git switch feature
git rebase main
git log --oneline --graph

* 1ff474b F2
* bf9149e F1
* 8842fb5 M1
* 8766865 A

履歴は一直線になり、まるでM1の後に作業を始めたかのようです。ハッシュに注目してください。F1は 5a71e3c から bf9149e に、F2は 082cc6a から 1ff474b に変わりました。Gitがそれらを書き換えたためで、rebaseに注意が必要な理由です。

mergeとrebaseの比較

項目MergeRebase
履歴の形マージコミットを含む分岐したグラフ一直線
既存のコミット変更されない新しいハッシュで書き換えられる
コンフリクトマージコミットで一度だけ解決再適用する各コミットで対応が必要な場合がある
共有ブランチでの安全性安全安全ではない
最適な用途完成した作業を main に取り込むレビュー前に自分のブランチを更新する

ヒント:迷ったら、自分のブランチを他に誰が持っているか確認しましょう。誰もいなければrebaseは安全です。同僚が取得済みならmergeを使います。

rebaseの黄金律

自分のリポジトリの外に存在するコミットをrebaseしてはいけません。rebaseの後、ブランチはサーバー上のコピーと一致しなくなるため、プッシュには強制が必要になります。同僚が古いコミットを土台に作業していた場合、その履歴はあなたの履歴と食い違い、解消は大変です。

自分専用のフィーチャーブランチをrebaseするのは問題ありません。main や他の人が使うブランチをrebaseするのはいけません。

安全なチームワークフロー

この手順なら、誰も驚かせずに履歴をきれいに保てます。多くのチームがCIパイプラインの前に使っている方法でもあり、GitHub Actions CI/CDガイド(英語)のパイプラインもその一例です。

git switch feature
git fetch origin
git rebase origin/main        # or: git pull --rebase
# fix conflicts, then: git add <file> && git rebase --continue
git push --force-with-lease   # only on your own branch

--force-with-lease は、前回のfetch以降に誰かがサーバーのブランチへプッシュしていた場合、上書きを拒否します。通常の --force は黙ってそれを消してしまいます。プルリクエストが承認されたら、main にマージします。

失敗したrebaseを元に戻す方法

rebaseは破壊的に見えますが、古いコミットはしばらくGitの reflog に残るので、元に戻せます。

git reflog                    # find the commit before the rebase
git reset --hard HEAD@{5}     # example position, check reflog first

リスクのあるrebaseの前に git branch backup でバックアップブランチを作っておけば、復旧は1コマンドで済みます。コンテナでデータベースやツールを動かしていますか?初心者向けDockerチュートリアル(英語)もご覧ください。

まとめ

mergeは事実を残し、rebaseは履歴を整えます。自分のブランチを最新にするにはrebase、成果を届けるにはmergeを使い、他の人が依存している履歴は決して書き換えないでください。

よくある質問

git mergeとgit rebaseの違いは何ですか?

mergeはマージコミットで2つのブランチを結合し、既存のコミットをすべて残します。rebaseは自分のコミットを別のブランチの上に移して書き換え、直線的な履歴を作ります。

mergeとrebaseのどちらを使うべきですか?

自分のフィーチャーブランチを最新に保つにはrebase、mainのような共有ブランチに届けるときはmergeを使います。他の人がそのブランチを共有している場合は常にmergeです。

git rebaseは危険ですか?

プライベートなブランチでは安全ですが、共有ブランチではコミットのハッシュを書き換えるため危険です。問題が起きたときは、バックアップブランチとreflogで復旧できます。

force-with-leaseは何をしますか?

リモートブランチが前回見た位置のままである場合にのみ強制プッシュするため、同僚の新しいコミットを誤って上書きすることがありません。

rebaseでコミットは消えますか?

消えません。同じ変更を持つ新しいコミットが作られ、古いコミットはGitが整理するまでreflogに残ります。

さらに学ぶ(英語の記事)

Stack Quora と協力する

テスト、WordPress、SEOでお困りですか?

私たちは、チームがより良いソフトウェアを提供し、サイトを成長させるお手伝いをしています。取り組んでいる内容をお知らせいただければ、明確な次のステップをご提案します。

読み続けてください

詳しいガイドはこちら テスト、AI、最新の開発

この記事は気に入りましたか?トピックを選択して、最新のチュートリアルに直接アクセスしてください。

人工知能

AI 幻覚の説明: 言語モデルが物事をでっち上げる理由とそれを軽減する方法

AI 幻覚について説明しました。幻覚とは何か、言語モデルが幻覚を生成する理由、一般的な種類、グラウンディングとプロンプトで幻覚を軽減する方法、そして私たちが実行した簡単なチェックです。

記事を読む →
DevOps

環境変数の説明: .env ファイル、シークレット、および設定が正しく行われている

実行した Python の例を使用して環境変数について説明します。環境変数の読み取りと設定、すべての値が文字列である理由、.env ファイル、プロセスの継承、シークレット、検証について説明します。

記事を読む →
ソフトウェア開発

API レート制限の説明: アルゴリズム、ヘッダー、および 429 エラーの処理

API レート制限については、実行したシミュレーションで説明します。トークン バケット、固定ウィンドウ、スライディング ウィンドウ、429 応答、レート制限ヘッダー、バックオフによる再試行、およびテスト制限です。

記事を読む →
テスト自動化

Python でのモッキング:unittest.mock、patch、およびテストを嘘にする間違い

Python でのunittest.mockによるモック、テスト済み: モックとreturn_value、side_effect、名前が使用されている場所のパッチ、仕様と自動仕様、日付のモック、およびよくある間違い。

記事を読む →
ソフトウェアテスト

コードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味

実際のcoverage.pyの実行でコードカバレッジを説明: 行、分岐、条件のカバレッジ、レポートの読み取り、100%のカバレッジでもバグを見逃す可能性がある理由、および賢明なターゲット。

記事を読む →
データベースとSQL

SQL における DELETE、TRUNCATE、DROP: 違い、ロールバック、およびそれぞれをいつ使用するか

DELETE、TRUNCATE、DROP について、テスト済み SQL を使用して説明します。それぞれの削除内容、ロールバック、トリガー、ID リセット、速度、PostgreSQL、MySQL、SQL Server、SQLite の違いについて説明します。

記事を読む →
データベースとSQL

SQL ビューの説明: 作成、使用、落とし穴の回避、例を示します

SQL ビューについて、実行したクエリとともに説明しました。ビューの作成、ライブ結果、列の非表示、パフォーマンス、更新可能なビューと具体化されたビュー、壊れた依存関係、ベスト プラクティスについて説明します。

記事を読む →
ソフトウェア開発

TypeScript インターフェイスと型: 実際の違い、コンパイラでテスト

TypeScript インターフェイスと型、実際のコンパイラでチェック: 両方でできること、片方だけでできること、宣言のマージ、拡張と交差、および従うべき簡単なルール。

記事を読む →
ソフトウェア開発

Python *args と **kwargs の説明: 柔軟な関数と明確な例

Python の *args と **kwargs について、実行したコードで説明しました。パッキングとアンパッキング、パラメーターの順序、キーワードのみの引数と位置のみの引数、デコレーター、一般的なエラーです。

記事を読む →
ソフトウェア開発

Python Lambda 関数: 構文、実際の用途、および使用すべきでない場合

Python のラムダ関数について、実行したコードとともに説明します。構文、キーによるソート、マップとフィルター、クロージャー、遅延バインディング トラップ、通常の def がより適切な選択である場合。

記事を読む →
人工知能

AIエージェントとは何ですか?シンプルなエージェント ループを実行できる仕組み

AIエージェントとは何ですか?エージェント ループ、ツール、メモリ、ガードレール、実行した小さな Python ループ、実際のリスク、およびシンプルなチャットボットがより良い選択である場合についてのわかりやすいガイドです。

記事を読む →
DevOps

モニタリングと可観測性: ログ、メトリクス、トレースによる本当の違い

モニタリングと可観測性について説明: 既知および未知の障害、ログ、メトリクスとトレース、チェックアウト インシデントのウォークスルー、ゴールデン シグナル、OpenTelemetry、および便利なアラート。

記事を読む →
DevOps

Docker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する

Docker ボリュームとバインド マウントについて説明します。コンテナ データが消える理由、名前付きボリューム、バインド マウント、tmpfs、Compose の例、バックアップ、アクセス許可、およびそれぞれをいつ使用するかについて説明します。

記事を読む →
テスト自動化

TDD と BDD: 主な違い、1 つの機能が両方の方法で構築され、それぞれをいつ使用するか

TDD と BDD は、両方の方法で構築された 1 つの割引機能で説明されています。実行したコードによるレッド-グリーン-リファクタリング、Given-When-Then シナリオ、ツール、トレードオフ、およびそれぞれをいつ使用するかです。

記事を読む →
ソフトウェア開発

Git mergeとrebaseの違い:例と使い分け

Git mergeとrebaseの違いを、実際のログ出力、比較表、rebaseの黄金律、安全なチームワークフローで解説します。

記事を読む →
ソフトウェア開発

Pythonのリスト内包表記:構文・例・使うべきでない場面

Pythonのリスト内包表記を解説:構文、フィルタ、if-else、ネストしたループ、実測した処理時間、そして通常のforループの方が良い場面。

記事を読む →
データベースとSQL

SQL JOINを例で解説(Inner・Left・Right・Full)

サンプルのテーブルとクエリでSQL JOINを順に解説。INNER、LEFT、RIGHT、FULL、CROSS、SELFに加え、よくある間違いとパフォーマンスのコツも紹介します。

記事を読む →