【Git】分かりやすく解説！fetch, merge, pull, rebase の違いと使い分け

# はじめに
<!-- 発端や概要を記載 -->
こんにちは、エンジニア3年目の嶋田です。
この記事を開いていただきありがとうございます！

私がエンジニアとして働き始めてから、チームメンバーとのコードの統合においてGitのコマンドを効率的に使用することがどれほど重要かを学んできました。特にリモートリポジトリの変更をどのようにローカルに反映させるかは、開発のスムーズさを左右します。

`git rebase`を使用することが多いのですが、
他のコマンドとの使い分けや違いを理解できている自信がなかったのでまとめてみました。

Gitのコマンドの使い分けについて混乱しやすい点を解説したいと思います。

# 目次
- [Gitコマンドの使い分け](#Gitコマンドの使い分け)
- [git fetchの使い方](#git-fetchの使い方)
- [git mergeの使い方](#git-mergeの使い方)
- [git pullの使い方](#git-pullの使い方)
- [git rebaseの使い方](#git-rebaseの使い方)
- [まとめ](#まとめ)

## Gitコマンドの使い分け
Gitを使う上で、「他の人がpushした内容をどう取り込むか」は非常に重要なポイントです。この問題に対応する主要なコマンドには`git fetch`、`git merge`、`git pull`、`git rebase`があります。

## git fetchの使い方
```
git fetch
```
`git fetch`コマンドはリモートリポジトリから最新の情報をローカルリポジトリに取り込むものです。
ただ、現在チェックアウトしているブランチには自動的にマージされません。
これはどういうことかというと、リモートリポジトリの最新の状態を取得しても、自分の作業中のコードには影響がないということです。

具体的には、`git fetch`を実行すると、リモートリポジトリにある全てのブランチの最新情報がローカルの対応するトラッキングブランチに保存されます（例えば`origin/main`）。
しかし、これらの変更は自動的にあなたの現在のブランチ（例えば`main`）には統合されません。

これにより、リモートの変更を確認し、必要に応じて選択的にマージするか、特定のブランチをチェックアウトして作業を開始することができます。これは、他の開発者の変更によって自分の作業中のコードが意図せず変更されることを防ぐのに役立ちます。

### git fetchと他のコマンドとの違い
`git fetch`と似ているコマンドに`git pull`がありますが、重要な違いがあります。`git pull`は`git fetch`の後に自動的に`git merge`を行います。つまり、`git pull`を使うと、リモートの変更をただちに現在のブランチにマージしてしまうため、リモートの変更内容を確認する前に自分の作業に影響が出る可能性があります。

`git fetch`を使用することで、リモートの変更を確認した上で、それらをどのように取り入れるかを自分で管理することができます。これは、特に複雑なプロジェクトや、安定性が重視される状況で有効です。自分のタイミングで変更を取り入れることができるため、予期せぬエラーやコンフリクトを避けることが可能になります。

## git mergeの使い方
```
git merge <branch>
```
`git merge`コマンドは、特定のブランチ（例えば`main`ブランチなど）からの変更を現在チェックアウトしているブランチに統合するために使用します。
このコマンドは、安定した変更を現在の作業に取り入れたいとき、または機能の開発が完了して本流のブランチにマージしたいときに非常に便利です。

具体的な使用例としては、あなたが`feature`ブランチで新しい機能を開発し終えた後、それを`main`ブランチに統合したい場合に使います。まず、`main`ブランチに切り替え(`git checkout main`)、次に`git merge feature`を実行します。この操作により、`feature`ブランチの変更が`main`ブランチに統合されます。

### git mergeと他のコマンドとの違い
`git merge`は、リモートリポジトリからの変更を取り入れる`git pull`と似ていますが、重要な違いがあります。
`git pull`は、基本的に`git fetch`と`git merge`を一連の操作として自動的に実行するコマンドです。
つまり、`git pull`はリモートの最新の変更を自動的に現在のブランチにマージするのに対し、`git merge`はより制御された方法で、特定のブランチの変更を明示的に選択して現在のブランチに統合するために使われます。

また、`git rebase`との違いも重要です。`git merge`は、異なるブランチの履歴を維持しつつ、それらを一つのブランチに統合するために使います。
これに対し、`git rebase`はブランチの変更を現在のブランチの履歴の上に再適用することで、より清潔な一直線の履歴を作成します。

`git merge`を使用することで、プロジェクトの履歴にブランチ間の関係が「マージコミット」として表示され、どの変更がどのブランチから来たのかが明確になります。これは大規模なプロジェクトや多くの開発者が関与するプロジェクトで役立つ情報です。

## git pullの使い方
```
git pull
```
`git pull`コマンドは、`git fetch`と`git merge`の二つの操作を一つのコマンドで自動的に行うことができます。
これにより、リモートリポジトリから最新の変更を取得し、その変更を直ちに現在のブランチにマージすることができます。
このコマンドは、日々の開発作業で頻繁に使われ、リモートの最新の変更を迅速に取り入れる必要がある場合に特に便利です。

具体的には、あなたが作業しているブランチでリモートの最新の変更を取り入れたい場合に`git pull`を使います。
たとえば、他のチームメンバーが`main`ブランチに新しいコミットをプッシュした場合、あなたがその`main`ブランチにいるときに`git pull`を実行することで、その変更を自分のローカルの`main`ブランチに直接取り込むことができます。

### git pullと他のコマンドとの違い
`git pull`は、`git fetch`に続いて`git merge`を自動的に実行します。これにより、手動でこれらのコマンドを個別に実行する手間が省け、より効率的に作業を進めることができます。ただし、自動的にマージが行われるため、予期せぬマージの問題やコンフリクトが発生するリスクも伴います。

`git fetch`後に手動で`git merge`を行う場合は、リモートの変更をローカルに取り込む前に詳細なレビューを行うことができますが、`git pull`を使用すると、そのレビューの機会が減少します。これは、特に大規模なプロジェクトや重要なリリース前の作業では、慎重に考える必要があります。

また、`git pull`と似た機能を持つ`git pull --rebase`もありますが、これはマージではなくリベースを行います。リベースを使うと、プロジェクトのコミット履歴をより綺麗に一直線に保つことができますが、リモートの変更を自分のローカルの変更の上に再適用するため、場合によってはより複雑なコンフリクトが発生する可能性があります。

このように、`git pull`は便利ですが、使用する状況に応じて適切なコマンドを選ぶことが重要です。

## git rebaseの使い方
```
git rebase
```
`git rebase`は、自分のローカルブランチのコミットをリモートリポジトリ（または別のブランチ）の最新の変更の上に再適用するコマンドです。これにより、プロジェクトの履歴がクリーンで一直線に整理され、履歴が見やすくなります。特に、プロジェクトのメインブランチの変更を取り入れたい時や、自分のフィーチャーブランチを最新状態に保ちたい時に有効です。

### git rebaseの具体的な使い方
たとえば、`feature`ブランチで作業をしていて、`main`ブランチの最新の変更を取り込みたい場合、次の手順で`git rebase`を実行します。

1. 最初に`main`ブランチの最新の変更をローカルに取得します。
   ```
   git checkout main
   git pull
   ```

2. 次に、`feature`ブランチに戻ります。
   ```
   git checkout feature
   ```

3. `feature`ブランチで`git rebase main`を実行します。
   ```
   git rebase main
   ```
これにより、`feature`ブランチの変更が`main`ブランチの最新の変更の上に再適用されます。

### git rebaseと他のコマンドとの違い
`git rebase`と`git merge`はよく比較されますが、その主な違いは履歴の整理の仕方にあります。`git merge`はブランチをマージする際に新しいマージコミットを作成し、ブランチ間の変更履歴を保存します。これに対し、`git rebase`はあたかもそれらの変更が最初からそのブランチで行われたかのように履歴を再構成します。これにより履歴が一直線に保たれ、変更が追いやすくなりますが、既に公開されたコミットをリベースする際は他の開発者に影響を与える可能性があるため注意が必要です。


## まとめ

以下の表に、今回説明したGitコマンドの主な特徴と使用シナリオをまとめました。

| コマンド       | 説明                                                         | 自動マージ | 主な使用シナリオ                                      |
|--------------|------------------------------------------------------------|-----------|----------------------------------------------------|
| `git fetch`  | リモートリポジトリから最新の情報を取得するがマージはしない。              | ×         | リモートの変更を確認し、必要に応じてマージしたい場合。             |
| `git merge`  | 指定したブランチからの変更を現在のブランチに統合する。                  | ◯         | 安定した変更を現在の作業ブランチに統合したい場合。                |
| `git pull`   | `git fetch` に続いて `git merge` を自動的に実行する。             | ◯         | リモートの最新の変更を迅速に現在のブランチに統合したい場合。        |
| `git rebase` | 自分のローカルブランチのコミットをリモートの最新変更の上に再適用する。 | ×         | 履歴を一直線に整理し、他のブランチの変更を取り込みたい場合。         |


`git fetch`、`git merge`、`git pull`、`git rebase` それぞれが異なる状況で役立ちます。
どのコマンドを使うかは、現在の作業の状況とプロジェクトの履歴をどのように管理したいかに依存します。
この記事が皆さんのGit操作の助けになれば幸いです。私自身まだまだ勉強中なので、何か問題がありましたら教えてください！

読んでいただき、ありがとうございました！