git rebase -i の活用

`git rebase -i`ではインタラクティブモードと呼ばれる方法でターミナルと対話的に操作を進めることができます。
ローカルのコミット履歴を綺麗に整理するのに役立つコマンドです。

## 注意

リモートに既にプッシュされているコミットに対して`git rebase -i`コマンドで操作を行うのは注意が必要です。
操作を行ったローカルのコミットに対して新しいコミットハッシュが生成され、リモートとローカルの履歴が一致しなくなるためです。

他の開発者がチェックアウトしていないブランチや、チームの合意が得られている場合なら、`--force`オプションを使用し強制プッシュすることによって、履歴を上書きすることができます。

## 直前のコミット内容の修正

直前のコミットに対して修正を行いたい場合は、`git rebase -i`を使用する必要はありません。

1. 修正したいファイルに変更を加え、ステージングする

   ```shell
   git add <修正したいファイル>
   ```

2. `--amend`オプションを使用してコミットする

   ```shell
   git commit --amend
   ```

## コミット内容の修正

1. コミットログの確認

   ```shell
   git log --oneline
   ```

2. インタラクティブモードを開始

   例えば、修正したいコミットが三番目だったら下記のようにする。

   ```shell
   git rebase -i HEAD~3
   ```

3. エディタで修正したいコミットを選択

   エディタが開き、下記のように表示される。`git log --oneline`とは逆の順番で表示されるので注意。

   ```shell
   pick f392171 Commit message 1
   pick d7322aa Commit message 2
   pick c9318f4 Commit message 3
   ```

   修正したいコミットの`pick`の文字を`edit`に書き換えて、保存して終了。

4. ワークツリーで変更を加える

   エディタを修了させた時点で、ワークツリーは選択したコミットの状態になっています。
   この状態でファイルに変更を加え、`git add`でステージングしましょう。

5. 変更をコミットする

   ```shell
   git commit --amend
   ```

6. リベースを完了し、最新のコミットに戻ってくる

   ```shell
   git rebase --continue
   ```

## コミットメッセージのみ修正

1. コミットログの確認

   ```shell
   git log --oneline
   ```

2. インタラクティブモードを開始

   例えば、修正したいコミットが三番目だったら下記のようにする。

   ```shell
   git rebase -i HEAD~3
   ```

3. エディタで修正したいコミットを選択

   エディタが開き、下記のように表示される。`git log --oneline`とは逆の順番で表示されるので注意。

   ```shell
   pick f392171 Commit message 1
   pick d7322aa Commit message 2
   pick c9318f4 Commit message 3
   ```

   修正したいコミットの`pick`の文字を`reword`に書き換えて、保存して終了。

4. コミットメッセージを入力するエディタが開くので、新しいメッセージに書き換えて、保存して終了。

## コミットの並べ替え、削除

1. コミットログの確認

   ```shell
   git log --oneline
   ```

2. インタラクティブモードを開始

   例えば、修正したいコミットが三番目だったら下記のようにする。

   ```shell
   git rebase -i HEAD~3
   ```

3. コミットの並べ替え、または削除を行う

   エディタが開き、下記のように表示される。`git log --oneline`とは逆の順番で表示されるので注意。

   ```shell
   pick f392171 Commit message 1
   pick d7322aa Commit message 2
   pick c9318f4 Commit message 3
   ```

   - 削除を行いたい場合は、エディタに表示されているコミットを丸ごと削除する。
   - 順番を並び替えたい場合は、エディタに表示されているコミットの順番を並べ替える。

## コミットをまとめる

1. コミットログの確認

   ```shell
   git log --oneline
   ```

2. インタラクティブモードを開始

   例えば、修正したいコミットが三番目だったら下記のようにする。

   ```shell
   git rebase -i HEAD~3
   ```

3. エディタで修正したいコミットを選択

   エディタが開き、下記のように表示される。`git log --oneline`とは逆の順番で表示されるので注意。

   ```shell
   pick f392171 Commit message 1
   pick d7322aa Commit message 2
   pick c9318f4 Commit message 3
   ```

   修正したいコミットの`pick`の文字を`squash`に書き換えて、保存して終了。

4. スカッシュするコミットのメッセージを編集する

   再びエディタが開くので、コミットをまとめたことに対するコミットメッセージを入力する。  
   そのままでもよい。

   保存して終了。

## コミットを分割する

1. コミットログの確認

   ```shell
   git log --oneline
   ```

2. インタラクティブモードを開始

   例えば、修正したいコミットが三番目だったら下記のようにする。

   ```shell
   git rebase -i HEAD~3
   ```

3. エディタで修正したいコミットを選択

   エディタが開き、下記のように表示される。`git log --oneline`とは逆の順番で表示されるので注意。

   ```shell
   pick f392171 Commit message 1
   pick d7322aa Commit message 2
   pick c9318f4 Commit message 3
   ```

   修正したいコミットの`pick`の文字を`edit`に書き換えて、保存して終了。

4. 選択したコミットの変更分をステージング前の状態にする

   この時点では、選択したコミットの変更分はコミット済みになっているので、ステージング前の状態にする。
   （`git commit`も`git add`もされていないワークツリーの変更しかない状態に戻す。）

   ```shell
   git reset HEAd^
   ```

5. 分割したいの変更分だけステージングしてコミットする

   ```shell
   git add <分割したい変更のあるファイル>
   git commit
   ```

6. 残りの変更分をステージングしてコミットする

   ```shell
   git add .
   git commit
   ```

7. リベースを完了し、最新のコミットに戻ってくる

   ```shell
   git rebase --continue
   ```

## コンフリクトしたら…

`git rebase —continue`を行ったときにコンフリクトが起きることがあります。

コンフリクトが起きても、まずは慌てずにそのコンフリクトの解消を試みるか、`git rebase -i`を行う前の状態に戻すかを決めましょう。

### コンフリクトを解消する場合

1. コンフリクトの発生しているファイルを開く

2. 適切に変更を加え、不要なマーカーを取り除く

   ```tsx
   <<<<<<< HEAD
                 await deleteQA(flashcardId, qaId);
   =======
                 const { success, message } = await deleteQA(flashcardId, qaId);
                 setIsShowing(true);
                 setType(success ? "success" : "error");
                 setMessage(message);
   >>>>>>> c3ef6b9 (QAndAEditMenuListコンポーネントの修正)
   ```

3. ステージングする

4. `git rebase --continue`を実行する

5. 再度コンフリクトが発生したら`1 ~ 4`の手順を繰り返す

### リベース前の状態に戻す場合

`git rebase --abort`を実行する