[Git] Revert より Reset を使ったほうがいい事例紹介

### 問題となった状態

#### 初期状態

1. `develop` ブランチには以下のコミットがあります：

    ```
    * commit3 - Develop Feature C
    * commit2 - Develop Feature B
    * commit1 - Initial commit
    ```

2. `feature-a` ブランチには以下のコミットがあります：

    ```
    * commit5 - Feature A2
    * commit4 - Feature A1
    ```

3. `feature-b` ブランチには以下のコミットがあります：

    ```
    * commit7 - Feature B2
    * commit6 - Feature B1
    ```

#### 誤ったマージ

`feature-a` ブランチに `feature-b` ブランチを誤ってマージしました：

```bash
git checkout feature-a
git merge feature-b
```

これにより、`feature-a` ブランチの履歴は以下のようになります：

```
* merge-commit-feature-b - Merge branch 'feature-b'
* commit7 - Feature B2
* commit6 - Feature B1
* commit5 - Feature A2
* commit4 - Feature A1
```

#### マージの取り消し

この誤ったマージを `git revert` で取り消します：

```bash
git revert -m 1 <merge-commit-feature-b-hash>
```

これにより、`feature-a` ブランチの履歴は以下のようになります：

```
* revert-merge-commit-feature-b - Revert "Merge branch 'feature-b'"
* merge-commit-feature-b - Merge branch 'feature-b'
* commit7 - Feature B2
* commit6 - Feature B1
* commit5 - Feature A2
* commit4 - Feature A1
```

#### `feature-a` ブランチの `develop` へのマージ

`feature-a` ブランチを `develop` にマージします：

```bash
git checkout develop
git merge feature-a
```

これにより、`develop` ブランチの履歴は以下のようになります：

```
* merge-commit-feature-a - Merge branch 'feature-a'
* revert-merge-commit-feature-b - Revert "Merge branch 'feature-b'"
* merge-commit-feature-b - Merge branch 'feature-b'
* commit7 - Feature B2
* commit6 - Feature B1
* commit5 - Feature A2
* commit4 - Feature A1
* commit3 - Develop Feature C
* commit2 - Develop Feature B
* commit1 - Initial commit
```

#### `feature-b` ブランチの `develop` への再マージ

`feature-b` ブランチを `develop` にマージしようとします：

```bash
git checkout develop
git merge feature-b
```

### コンフリクトの発生

この再マージの際に、Gitは以下のようにコンフリクトを検出します：

- `develop` ブランチには既に `feature-b` の変更（`commit6` と `commit7`）が含まれており、それが `revert-merge-commit-feature-b` によって取り消されています。
- そのため、`feature-b` の同じ変更を再適用しようとすると、既に存在する `revert-merge-commit-feature-b` と衝突します。

### 対策

`reset` を使いましょう。この方法では、`feature-a` ブランチの状態を誤って `feature-b` をマージする前の状態に戻し、その状態を `develop` にマージします。

#### `reset` を使った解決法

##### `feature-a` ブランチのリセット

`feature-a` ブランチを誤って `feature-b` をマージする前の状態にリセットします。

1. **`feature-a` ブランチにチェックアウト**：

    ```bash
    git checkout feature-a
    ```

2. **リセットポイントのコミットハッシュを確認**：
   `feature-a` ブランチを誤って `feature-b` をマージする前のコミット（`commit5`）のハッシュを確認します。

    ```bash
    git log --oneline
    ```

    例えば、リセットしたいコミットハッシュが `commit5` の場合：

3. **`feature-a` ブランチをリセット**：

    ```bash
    git reset --hard <commit5のハッシュ>
    ```

    これにより、`feature-a` ブランチの履歴は以下のようになります：

    ```
    * commit5 - Feature A2
    * commit4 - Feature A1
    ```

4. **リモートリポジトリに強制プッシュ**：
   リセット後の状態をリモートリポジトリに反映させます。

    ```bash
    git push --force
    ```

##### `develop` ブランチへのマージ

1. **`develop` ブランチにチェックアウト**：

    ```bash
    git checkout develop
    ```

2. **`feature-a` ブランチをマージ**：

    ```bash
    git merge feature-a
    git push
    ```

    これにより、`develop` ブランチの履歴は以下のようになります：

    ```
    * merge-commit-feature-a - Merge branch 'feature-a'
    * commit5 - Feature A2
    * commit4 - Feature A1
    * commit3 - Develop Feature C
    * commit2 - Develop Feature B
    * commit1 - Initial commit
    ```

##### `feature-b` ブランチの `develop` へのマージ

1. **`feature-b` ブランチを `develop` にマージ**：

    ```bash
    git checkout develop
    git merge feature-b
    git push
    ```

    これにより、`develop` ブランチの履歴は以下のようになります：

    ```
    * merge-commit-feature-b - Merge branch 'feature-b'
    * commit7 - Feature B2
    * commit6 - Feature B1
    * merge-commit-feature-a - Merge branch 'feature-a'
    * commit5 - Feature A2
    * commit4 - Feature A1
    * commit3 - Develop Feature C
    * commit2 - Develop Feature B
    * commit1 - Initial commit
    ```

### まとめ

この方法では、`feature-a` ブランチを誤って `feature-b` をマージする前の状態に戻し、その状態を `develop` にマージします。これにより、`feature-a` の変更が正しく `develop` に統合され、その後 `feature-b` の変更を再度 `develop` にマージしてもコンフリクトが発生しません。