git rebaseメモ

## 内容
gitでrebaseというコマンドがあります、そのメモです。

## 用途
<b>複数のコミットを１つにする</b>
複数のコミットを１つにまとめます。

<b>ブランチのベースを変更する(履歴を綺麗に保つ)</b>
例えば、自分が作業しているブランチから分岐した元のブランチ（例えば、main ブラン チ）に新しい変更が加わった場合、それらの変更を自分のブランチに取り込み、まるで自分のブランチが最新のmain ブランチから分岐したかのように履歴を再構成します。

## 状況例
以下の状況を想定します。
・作業ブランチに複数のコミットがある
・作業ブランチはmainブランチより作っている
・mainブランチは更新されている
上記状況に対し、作業ブランチに対し、最新のmainより派生した形で、作業ブランチのコミットを一つにし対応する(作業ブランチはmainの更新を取り込んでいる)

指定された状況に対応するための手順は、まず作業ブランチのコミットを1つにまとめた後、`main`ブランチの最新の変更を作業ブランチに取り込む、という流れになります。以下に、具体的なステップを示します。

### ステップ1: 作業ブランチのコミットを1つにまとめる

1. 作業ブランチにチェックアウトします。
   ```bash
   git checkout <作業ブランチ名>
   ```
   
2. インタラクティブリベースを開始して、まとめたいコミットを選択します。ここで、`HEAD~N`はまとめたいコミットの数によって調整します。
   ```bash
   git rebase -i HEAD~N
   ```
   
   インタラクティブリベースのエディタが開いたら、最初のコミット以外を`squash`または`s`に変更して、1つにまとめます。

○以下まとめた例です。
・ブランチ例
2つのブランチ(main、test_br)があります。
```
apple@appurunoMacBook-Pro git_practice % git br
  main
* test_br
```
・複数あるコミットをま止めます、３つのコミットを１つにします。
```bash
apple@appurunoMacBook-Pro git_practice % git rebase -i HEAD~3
```
・こういう画面になるのでまとめたい箇所に`s`もしくは`squash`を入力します。
```bash
pick 6786fd0 test3
s 047021b test4
s 584eb1f test5

# Rebase 87db741..584eb1f onto 87db741 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
-- INSERT --
```
・エディタ処理終了後、以下でコミットが１つになります。
```bash
[detached HEAD ad69c9e] test3
 Date: Sat Mar 16 16:41:50 2024 +0900
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/test_br.
```

(rebase前)
ブランチ(test_br)に、mainから作成後、コミットが３つあります。
```bash
apple@appurunoMacBook-Pro git_practice % git log --graph --all 
* commit 584eb1f1169847ff05000feba849de51d6f916b7 (HEAD -> test_br)
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:53:08 2024 +0900
| 
|     test5
| 
* commit 047021b5121c21e7aa344a36c37d7afe1e0b7cdd
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:42:41 2024 +0900
| 
|     test4
| 
* commit 6786fd094577da7a51a1e6df1083adc51a367513
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:41:50 2024 +0900
| 
|     test3
|   
| * commit 9cbca0e69e64000df4abf1dc1bf649f64b8b0821 (main)
|/  Author: sawa <you@example.com>
|   Date:   Sat Mar 16 16:50:26 2024 +0900
|   
|       testmain修正
```

(rebase後)
ブランチ(test_br)に、mainから作成後、コミットが１つになりました。
```bash
apple@appurunoMacBook-Pro git_practice % git br
  main
* test_br
apple@appurunoMacBook-Pro git_practice % git rebase -i HEAD~3
[detached HEAD ad69c9e] test3
 Date: Sat Mar 16 16:41:50 2024 +0900
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/test_br.
apple@appurunoMacBook-Pro git_practice % git log --graph --all
* commit ad69c9e9038ed127fb5d8f9b597d976914ca29e4 (HEAD -> test_br)
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:41:50 2024 +0900
| 
|     test3
|     
|     test4
|     
|     test5
|   
| * commit 9cbca0e69e64000df4abf1dc1bf649f64b8b0821 (main)
|/  Author: sawa <you@example.com>
|   Date:   Sat Mar 16 16:50:26 2024 +0900
|   
|       testmain修正
| 
* commit 87db74113093458be833699f194b264d87a2ae6d
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:39:33 2024 +0900
| 
|     test2
| 
* commit 84195f5d4fd4468624869f7353ab7af6534d5e11
```

### ステップ2: `main`ブランチの最新変更をローカルの`main`に取り込む

1. `main`ブランチにチェックアウトします。
   ```bash
   git checkout main
   ```
   
2. `main`ブランチを最新の状態に更新します。
   ```bash
   git pull origin main
   ```

### ステップ3: 作業ブランチに`main`ブランチの変更を取り込む

1. 再び作業ブランチにチェックアウトします。
   ```bash
   git checkout <作業ブランチ名>
   ```
   
2. `main`ブランチの最新の変更を作業ブランチに取り込みます。これには`git rebase`を使用します。
   ```bash
   git rebase main
   ```

   この操作により、作業ブランチが`main`ブランチの最新の変更から派生したかのように履歴が再構成されます。この過程でコンフリクトが発生した場合は、それを解決し、`git rebase --continue`でリベースを続けます。

・コンフリクトが出て対応した例です。

```bash
apple@appurunoMacBook-Pro git_practice % git rebase main
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
error: could not apply ad69c9e... test3
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply ad69c9e... test3
```
ファイルが以下のようになっているので修正。
```
テスト１
テスト２
<<<<<<< HEAD
testmain修正
=======
テスト３
テスト4
テスト5
>>>>>>> ad69c9e (test3)
```
・修正後のstatus
```bash
apple@appurunoMacBook-Pro git_practice % git status
interactive rebase in progress; onto 9cbca0e
Last command done (1 command done):
   pick ad69c9e test3
No commands remaining.
You are currently rebasing branch 'test_br' on '9cbca0e'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")
apple@appurunoMacBook-Pro git_practice % git add test.txt 
apple@appurunoMacBook-Pro git_practice % git status
interactive rebase in progress; onto 9cbca0e
Last command done (1 command done):
   pick ad69c9e test3
No commands remaining.
You are currently rebasing branch 'test_br' on '9cbca0e'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   test.txt
```

・ステージングにあげます。
```bash
apple@appurunoMacBook-Pro git_practice % git add test.txt 
```

・ステージング後(add後)のstatusです。
```bash
apple@appurunoMacBook-Pro git_practice % git status
interactive rebase in progress; onto 9cbca0e
Last command done (1 command done):
   pick ad69c9e test3
No commands remaining.
You are currently rebasing branch 'test_br' on '9cbca0e'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")
apple@appurunoMacBook-Pro git_practice % git add test.txt 
apple@appurunoMacBook-Pro git_practice % git status
interactive rebase in progress; onto 9cbca0e
Last command done (1 command done):
   pick ad69c9e test3
No commands remaining.
You are currently rebasing branch 'test_br' on '9cbca0e'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   test.txt
```
・リベースを続けます。
完了するとsuccessのメッセージが出ます。
```bash
apple@appurunoMacBook-Pro git_practice % git rebase --continue
[detached HEAD c76f24e] test3 test4 test5 コンフリクト解消
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/test_br.
```
・ブランチtest_brは、あたかもmainの最新から修正した履歴になりました。
```bash
apple@appurunoMacBook-Pro git_practice % git log --graph --all
* commit c76f24e58450336e8eadb6f616fd7d606ca0e5ac (HEAD -> test_br)
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:41:50 2024 +0900
| 
|     test3
|     test4
|     test5
|     コンフリクト解消
| 
* commit 9cbca0e69e64000df4abf1dc1bf649f64b8b0821 (main)
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:50:26 2024 +0900
| 
|     testmain修正
| 
* commit 87db74113093458be833699f194b264d87a2ae6d
| Author: sawa <you@example.com>
| Date:   Sat Mar 16 16:39:33 2024 +0900
| 
|     test2
| 
* commit 84195f5d4fd4468624869f7353ab7af6534d5e11
  Author: sawa <you@example.com>
```

### ステップ4: 変更をリモートの作業ブランチに反映させる

リベース後の変更をリモートブランチに反映させるために、以下のコマンドを実行します。リベースを行った場合、履歴が変更されているため、通常のプッシュでは拒否される可能性があります。そのため、`--force`オプション（より安全な`--force-with-lease`オプションを推奨）を使います。

```bash
git push origin <作業ブランチ名> --force-with-lease
```

これで、作業ブランチのコミットが1つにまとめられ、さらに`main`ブランチの最新の変更が取り込まれた状態になります。これにより、作業ブランチが`main`の最新の状態から派生したように見え、その上で作業ブランチの変更が1つのコミットとして適用される形になります。

## 参考記事
https://qiita.com/KosukeSone/items/514dd24828b485c69a05

https://dev.classmethod.jp/articles/git-commit-matomeru/

https://qiita.com/futakuchi0117/items/0eafe586e88fe593c23f

https://envader.plus/article/268

https://zenn.dev/tana0102/articles/475d8952933af6