Git rebase 〜コミット履歴を綺麗にする技術〜

## はじめに

[ミライトデザイン Advent Calendar 2022](https://qiita.com/advent-calendar/2022/miraito-inc) 16 日の記事です。

昨日は [ほげさん](https://zenn.dev/suzuki_hoge)の [図解 DB インデックス](https://zenn.dev/suzuki_hoge/books/2022-12-database-index-9520da88d02c4f) でした。

データベースのインデックスについて図解で丁寧に書かれてます。
最近はあまり大きいデータに触る機会も少なく遅くなったらインデックス適当に張るか〜とふんわりとやってたのでこの機会に読んでとても学びになりました。

ほんと図解が超丁寧なのでこういう記事が書けるようになりたいです。

ほげさんほどではないですが、今年のアドベントカレンダーは気合を入れて書き上げました💪
今回はハンズオン形式でgit rebaseをマスターします💪

## Gitシリーズ記事まとめ

https://qiita.com/ucan-lab/items/33c63a402f533aa92f3e

# Git rebase 〜コミット履歴を綺麗にする技術〜

## 😈 あなたのコミット汚れてない？

```shell-session
$ git branch
  main
* topic-1
```

```shell-session
$ git log --oneline
c1aa188 (HEAD -> topic-1) テストを実装し直す
98e53cb ログイン機能のテストを仮実装
d67ab22 コードスタイルを修正
d2937bc やっぱり必要だったの元に戻す
4d5b8c4 不要なコードを削除
2d22576 タイプミスを修正
def5505 ログイン機能を実装
08f5d2c (main) first commit
```

ログイン機能を実装する目的で生やしたブランチですが、作業途中に出た修正のコミットなども混ざっています。

「タイプミスの修正」であれば「ログイン機能を実装」のコミットをひとまとめにしたいですし、「やっぱり必要だったから元に戻す」といったコミットは「不要なコードを削除」するコミットは不要ですね。

「ログイン機能のテストを仮実装」も次のコミットの「テストを実装し直す」で実装完成したのでまとめたいところです。

### 補足: おすすめ記事

https://qiita.com/suzuki-hoge/items/cc91877ce69527ced692

## コミットアンチパターン

- 「wip」「fix bugs」「fix ci」など変更理由が不明確なコミット
- 同じ内容のコミットメッセージが続くもの
- 何度も試行錯誤して追加、削除が多いコミット群
- どのチケット(Issue)と紐付いているのかわからない
- 機能追加とリファクタなど

コミットは書く時間より、読まれる時間の方が長いです。
開発時はコミットが汚くてもあまり困らないですが、保守をする読む側にとってはコミットの粒度やコミットメッセージが大切なので意識してコミットしていきましょう💪

## ゴール

git rebase を使ってコミットを整理できるところまで。

```shell-session
git log --oneline
b4e19ca (HEAD -> topic-1) ログイン機能のテストを実装
741889e ログイン機能を実装
a57c70e (main) first commit
```

目標はこのコミット履歴にすること。

## 作業ディレクトリの作成

```shell-session
$ mkdir git-handson
$ cd git-handson
```

※ハンズオンの際は必ずこのディレクトリでコマンドを実行してください。

# git rebase

前置きが長くなりましたが、ここからが本題の `git rebase` です。

## git rebase: コミットの指定

適当にコミットを作ります。

```shell-session
rm -rf .git; rm *.txt
git init; git branch -M main; :> README.md; git add .; git commit -m "first commit"
git switch -c topic-1
:> 1.txt; git add .; git commit -m "A の機能を実装"
:> 2.txt; git add .; git commit -m "B の機能を実装"
:> 3.txt; git add .; git commit -m "C の機能を実装"
:> 4.txt; git add .; git commit -m "wip"
:> 5.txt; git add .; git commit -m "E の機能を実装"
```

例えば下記のコミットがある例です。

```shell-session
git log --oneline

ff7dcc1 (HEAD -> topic-1) E の機能を実装
983669a wip
defb741 C の機能を実装
83918b0 B の機能を実装
48fdcc1 A の機能を実装
ded865a (main) first commit
```

`983669a wip` のコミットを編集したい場合は、 `defb741 C の機能を実装` のコミットを指定します。

```shell-session
$ git rebase -i <編集したいコミットの1つ前のコミットID>
```

```shell-session
$ git rebase -i defb741

pick 983669a wip
pick ff7dcc1 E の機能を実装
```

`コマンド コミットID コミットメッセージ` が列挙して表示されます。

`:wq` と保存して終了します。
中止したい場合は `:q!` と保存せず終了します。

`HEAD` の位置が `ff7dcc1 E の機能を実装` ここになっているので、ここから相対的にコミットを指定できます。
`HEAD~~` や `HEAD~2` と指定しても同様にコミットを指定できます。

```shell-session
$ git rebase -i HEAD~~
$ git rebase -i HEAD~2
```

とはいえ、コミット数が多くなると対象のコミットIDを探したり、何個前のコミットか数えるのが面倒になっていきます。
今回は main ブランチから切り出していて、 main ブランチは `48fdcc1 A の機能を実装` の1つ前のコミットを指しています。

```shell-session
$ git rebase -i main
pick 48fdcc1 A の機能を実装
pick 83918b0 B の機能を実装
pick defb741 C の機能を実装
pick 983669a wip
pick ff7dcc1 E の機能を実装
```

とすると `main` ブランチから差分であるコミットをすべて編集できるのでとても実用的です。

## git rebase: コマンドの解説

rebaseコマンドについて解説します。
この5つのコマンドを覚えればrebaseには特に困らないと思います。

```
p, pick: コミットをそのまま使用します。(コミットを並び替えたいだけだったり、編集しない場合はこれ)
r, reword: コミットはそのまま使用し、コミットメッセージのみ変更する
s, squash: 前のコミットにマージして、コミットメッセージを編集する。
f, fixup: 前のコミットにマージする。前のコミットメッセージをそのまま使用する。
d, drop: コミットを破棄する。
```

`git rebase -i main` するとvimエディタが起動します。

```shell-session
$ git rebase -i main

pick 48fdcc1 A の機能を実装
pick 83918b0 B の機能を実装
pick defb741 C の機能を実装
reword 983669a wip
pick ff7dcc1 E の機能を実装
```

`:wq` と保存して終了します。
再度 vim エディタが開き、コミットメッセージを変更できます。

```vim
wip

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sat Oct 8 15:03:48 2022 +0900
#
# interactive rebase in progress; onto ded865a
# Last commands done (4 commands done):
#    pick defb741 C の機能を実装
#    reword 983669a wip
# Next command to do (1 remaining command):
#    pick ff7dcc1 E の機能を実装
# You are currently editing a commit while rebasing branch 'topic-1' on 'ded865a'.
#
# Changes to be committed:
#	new file:   4.txt
#
```

下記のメッセージに変更してみます。

```vim
D の機能を実装
```

下記のようにコミットを変更できました。

```shell-session
git rebase -i main

[detached HEAD d9d9452] D の機能を実装
 Date: Sat Oct 8 15:03:48 2022 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 4.txt
Successfully rebased and updated refs/heads/topic-1.

git log --oneline

61572ad (HEAD -> topic-1) E の機能を実装
d9d9452 D の機能を実装
defb741 C の機能を実装
83918b0 B の機能を実装
48fdcc1 A の機能を実装
ded865a (main) first commit
```

## Git コミット履歴を綺麗にするハンズオン

### コミットを用意する

```
rm -rf .git; rm *.txt
git init; git branch -M main; :> README.md; git add .; git commit -m "first commit"
git switch -c topic-1
:> 1.txt; git add .; git commit -m "ログイン機能を実装"
:> 2.txt; git add .; git commit -m "タイプミスを修正"
:> 3.txt; git add .; git commit -m "不要なコードを削除"
:> 4.txt; git add .; git commit -m "やっぱり必要だったの元に戻す"
:> 5.txt; git add .; git commit -m "コードスタイルを修正"
:> 6.txt; git add .; git commit -m "ログイン機能のテストを仮実装"
:> 7.txt; git add .; git commit -m "テストを実装し直す"
echo hoge > 7.txt
echo hoge > 8.txt
```

### 事前準備

コミットを綺麗にする前に、作業途中のファイルがある場合はスタッシュに一時保存するかwipコミットをしておきましょう

コミットされていないファイルがあるとrebaseできないのでまずはstashします。

```
git status -s

 M 7.txt
?? 8.txt
```

```
git stash -u
```

-u オプションを付けると未追跡ファイルも含めてくれる

```
git status -s

# 何も表示されない
```

未追跡ファイルも含めてstashできたので、rebaseします。

:::note info
```
# -u オプションを付けると未追跡ファイルも含めてくれる
$ git stash -u

# 元に戻す
$ git stash pop
```

もしくは wip コミット作ってしまっても良いです。

```
$ git add .
$ git commit -m wip

# 元に戻す
$ git reset --soft HEAD^
```
:::

```
$ git rebase -i main

pick f5ef1b1 ログイン機能を実装
fixup 9339b9a タイプミスを修正
drop 0a10e4a 不要なコードを削除
drop e62d4d4 やっぱり必要だったの元に戻す
fixup f5e194c コードスタイルを修正
pick 421c9d2 ログイン機能のテストを仮実装
squash 4d69a31 テストを実装し直す
```

vim エディタが立ち上げるので下記のメッセージを...

```vim
# This is a combination of 2 commits.
# This is the 1st commit message:

ログイン機能のテストを仮実装

# This is the commit message #2:

テストを実装し直す

# ...
```

下記に修正して `:wq` 保存して閉じる

```vim
ログイン機能のテストを実装
```

```shell-session
git rebase -i main

[detached HEAD b4e19ca] ログイン機能のテストを実装
 Date: Sat Oct 8 15:47:33 2022 +0900
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 6.txt
 create mode 100644 7.txt
Successfully rebased and updated refs/heads/topic-1.
```

```shell-session
git log --oneline
b4e19ca (HEAD -> topic-1) ログイン機能のテストを実装
741889e ログイン機能を実装
a57c70e (main) first commit
```

お疲れ様です🍵
git rebaseを使ってコミット履歴を綺麗に出きました🤗
慣れるまでは時間かかりますが、覚えておいて損はないのでぜひマスターしましょう💪

ちょっと物足りない気がしたので、軽く補足を追加します。

## 補足: コンフリクトの解消

```shell-session
rm -rf .git; rm *.txt
git init; git branch -M main;
:> 1.txt; git add .; git commit -m "A"
:> 2.txt; git add .; git commit -m "B"
git switch -c topic-1
git switch -
echo "間違ったコード" > 3.txt; git add .; git commit -m "C"
git switch topic-1
:> 4.txt; git add .; git commit -m "D"
:> 5.txt; git add .; git commit -m "E"
echo "正しいコード" > 3.txt; git add .; git commit -m "F"
```

```
      D---E---F topic-1
     /
A---B---C main
```

各ブランチのコミットを確認します。

```shell-session
git log main --oneline

db8b276 (main) C
78a325c B
2b1d3b3 A
```

```shell-session
git log topic-1 --oneline

cf29cf2 (HEAD -> topic-1) F
019b3a5 E
b44cd1b D
78a325c B
2b1d3b3 A
```

```shell-session
git switch topic-1
git rebase main

Auto-merging 3.txt
CONFLICT (add/add): Merge conflict in 3.txt
error: could not apply cf29cf2... F
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 cf29cf2... F
```

リベースすると C コミットと F コミットでコンフリクトが発生します。
3.txt でコンフリクトが発生していますね。

コンフリクトが発生したファイルをすべて解決する必要があります。
解決したファイルを `git add` や `git rm` したあと `git rebase --continue` を実行します。

通常は `--continue` で良いですが、場合によってはコミットを `git rebase --skip` でスキップしたり
コミットを中止してgit rebaseする前の状態に戻すには `git rebase --abort` します。

コンフリクト解消中など、現在のファイルの状態を確認したい場合は git status をとりあえず実行します。

```shell-session
git status

interactive rebase in progress; onto db8b276
Last commands done (3 commands done):
   pick 019b3a5 E
   pick cf29cf2 F
  (see more in file .git/rebase-merge/done)
No commands remaining.
You are currently rebasing branch 'topic-1' on 'db8b276'.
  (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 added:      3.txt

no changes added to commit (use "git add" and/or "git commit -a")
```

`both added` になってるのがコンフリクトを起こしているファイルなのでこちらのファイルを開いて修正します。
また、差分を確認したい場合は git diff を実行します。

```shell-session
git diff

diff --cc 3.txt
index 073cc55,b0ba6b8..0000000
--- a/3.txt
+++ b/3.txt
@@@ -1,1 -1,1 +1,6 @@@
++<<<<<<< HEAD
 +間違ったコード
++||||||| parent of cf29cf2 (F)
++=======
+ 正しいコード
++>>>>>>> cf29cf2 (F)
```

コンフリクトが発生した箇所は `<<<<<<<`, `=======`, `>>>>>>>` で囲まれます。
それらの区切り文字を削除して正しい行のみ残していきます。

それでは `3.txt` ファイルを開いてコンフリクトを解消します。

```shell-session
vim 3.txt
```

```vim:3.txt
<<<<<<< HEAD
間違ったコード
||||||| parent of 7cb93ea (C2)
=======
正しいコード
>>>>>>> 7cb93ea (C2)
```

差分を確認し、競合が発生した箇所のファイルを修正します。

```shell-session
cat 3.txt

正しいコード
```

必要な行のみになっていることを確認します。

```shell-session
git add .
git status

interactive rebase in progress; onto f7e3ef6
Last commands done (3 commands done):
   pick 755ae24 E
   pick 7cb93ea C2
  (see more in file .git/rebase-merge/done)
No commands remaining.
You are currently rebasing branch 'topic-1' on 'f7e3ef6'.
  (all conflicts fixed: run "git rebase --continue")

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

```shell-session
git rebase --continue

F

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto db8b276
# Last commands done (3 commands done):
#    pick 019b3a5 E
#    pick cf29cf2 F
# No commands remaining.
# You are currently rebasing branch 'topic-1' on 'db8b276'.
#
# Changes to be committed:
#       modified:   3.txt
```

コミットメッセージを変更することもできますが、そのまま `F` のまま `:q` で閉じます。

```
[detached HEAD 90893c8] F
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/topic-1.
```

git rebase に成功したらこのメッセージが表示されます。
他にもコンフリクトするコミットがあれば繰り返し解決作業が発生します。

今回は競合が1つだけだったので、これでリベースが成功します。

```shell-session
$ git log --oneline
90893c8 (HEAD -> topic-1) F
5a64d71 E
85e1b68 D
db8b276 (main) C
78a325c B
2b1d3b3 A
```

コミットログがこのようになっていればOKです。

```
[Before]
      D---E---F topic-1
     /
A---B---C main

[After]
          D'---E'---F' topic-1
         /
A---B---C main
```

## 補足: git rebase --abort

```shell-session
$ git rebase --abort
```

`--abort` するとリベースは中止され、リベース前の状態に戻ります。

## 補足: Vim 矩形選択の練習

![git-rebase.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/ca0d1407-1523-61b7-d08f-5dc2e10c0165.gif)

```
rm -rf .git; rm *.txt
git init; git branch -M main; :> README.md; git add .; git commit -m "first commit"
git switch -c topic-1
:> 1.txt; git add .; git commit -m "A機能を実装"
:> 2.txt; git add .; git commit -m "wip"
:> 3.txt; git add .; git commit -m "wip"
:> 4.txt; git add .; git commit -m "wip"
:> 5.txt; git add .; git commit -m "wip"
:> 6.txt; git add .; git commit -m "wip"
:> 7.txt; git add .; git commit -m "wip"
```

```
git log --oneline

7ec6a8f (HEAD -> topic-1) wip
169da86 wip
1c6e373 wip
7e18f79 wip
942415f wip
d29009b wip
6a47888 A機能を実装
851b2b1 (main) first commit
```

すべてのwipコミットをA機能を実装のコミットにまとめてみましょう。
しかし、コミット数が多いと1つ1つ修正するのは手間なので矩形選択して修正してみましょう。

```
git rebase -i main
```

2つ目以降の `pick` をすべて `fixup` に変更してコミットをまとめたい時に矩形選択ができると便利です。
まず2行目の先頭にカーソルキーを配置して下記の手順で実行します。

- ※vimエディタが起動し、ノーマルモードから始まる想定です
- `j`: 矩形選択を開始する列までカーソルを移動する
- `control` + `v`: 矩形選択モードにする
- `j`: 矩形選択を終了する列までカーソルを移動する
- `iwc`: `pick` の文字が矩形選択されて、削除されて挿入モードへ移行します
- `fixup`: と入力する。(`f` でもOK)
- `Esc`: ノーマルモードへ戻る(入力した文字を挿入される)
- `:wq`: 保存して閉じる

矩形選択モードの時に使えるコマンドは `c` 以外にもいくつかあります。

|コマンド|動作|
|:----|:----|
|I|挿入モードに入る。ノーマルモードに戻るときに、選択領域の直前部分に文字が挿入される|
|A|挿入モードに入る。ノーマルモードに戻るときに、選択領域の末尾に文字が挿入される|
|r|選択領域を入力した1文字で置き換える|
|d|選択領域を削除する|
|c|選択領域を削除し、挿入モードに入る。ノーマルモードに戻るときに、選択していた領域の部分に入力した文字が挿入される|
|y|選択領域をヤンクする|

`I`, `c`　はよく使うと思います。 

## 補足: Git Merge と Git Rebase の違い

Mergeは「ブランチの合流」、Rebaseは「ブランチの根元の場所を付け替える」

- merge
  - 変更内容の履歴はそのまま残る
  - マージコミット分、履歴が複雑
- rebase
  - 履歴が単純になる
  - コミットIDが変更される

チームの運用方針にもよりますが、使い分けの一例です。

トピックブランチ(topic-xxx)に統合ブランチ(main)の最新コードを取り込む場合はrebaseを使用する。
統合ブランチにトピックブランチを取り込む場合は、トピックブランチでrebaseした後にmergeして取り込む。
(実際はローカルのトピックブランチでrebaseしてforce pushした後、GitHubのCreate a merge commitを選択してMerge pull requestするイメージです。)

![ScreenShot 2022-10-03 17.04.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/30769e60-d39a-49e6-073b-0b60b8e6a022.png)

http://nullnote.com/web/git/merge_rebase/

https://kray.jp/blog/git-pull-rebase/

https://backlog.com/ja/git-tutorial/stepup/04/

## 備考: コミットをちょこっと変えたい

直前のコミットや指定した1つのコミットだけサクっと直したいんだけど...
`git commit` の `--amend` オプションと `--fixup` オプションをご紹介します。

### 直前のコミットを変更を加える(--amend)

直前のコミットを変更したい場合は `git rebase` を使う必要はありません。
`git commit` の `--amend` オプションを使用します。 

```
rm -rf .git; rm *.txt
git init; git branch -M main;
echo 'first' > 1.txt; git add .; git commit -m "first commit"
echo 'second' > 2.txt; git add .; git commit -m "second commit"
```

git log でコミットを確認します。

```shell-session
git log --oneline

b7a249e (HEAD -> main) second commit
3c11e60 first commit
```

`git show` で最新のコミットの中身を確認します。
※コミットIDを指定しない場合は最新のコミットの中身が表示されます。

```shell-session
git show

commit b7a249eb6f90782e445823dbd516687c42d91e52 (HEAD -> main)
Author: ucan-lab <35098175+ucan-lab@users.noreply.github.com>
Date:   Thu Dec 8 21:07:07 2022 +0900

    second commit

diff --git a/2.txt b/2.txt
new file mode 100644
index 0000000..e019be0
--- /dev/null
+++ b/2.txt
@@ -0,0 +1 @@
+second
```

`2.txt` を変更してみます。

```shell-session
echo 'changed' >> 2.txt
```

```shell-session
git diff

diff --git a/2.txt b/2.txt
index e019be0..e388a7a 100644
--- a/2.txt
+++ b/2.txt
@@ -1 +1,2 @@
 second
+changed
```

:::note info
`git show` や `git diff` の差分の見方はこちら

https://www.atlassian.com/ja/git/tutorials/saving-changes/git-diff
:::

```shell-session
git add .
git commit --amend
```

vimエディタが立ち上がります。

```vim
second commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Dec 15 23:52:15 2022 +0900
#
# On branch main
# Changes to be committed:
#       new file:   2.txt
#
```

- `i` で挿入モードにして1行目を `changed second commit` に書き換えます。
- `:wq` で保存して閉じます。
- `#` はコメント行なので残したままでOK
- `.git/COMMIT_EDITMSG` に一時的にファイルが作成されていてこのファイルを編集してます。

```
git show

commit 992892111a1ad87c042c8b73830838c92037c4ee (HEAD -> main)
Author: ucan-lab <35098175+ucan-lab@users.noreply.github.com>
Date:   Fri Dec 16 01:16:21 2022 +0900

    changed second commit

diff --git a/2.txt b/2.txt
new file mode 100644
index 0000000..e388a7a
--- /dev/null
+++ b/2.txt
@@ -0,0 +1,2 @@
+second
+changed
```

`changed second commit` のコミットが変更されていることを確認できたらOKです。

```shell-session
echo 'updated' >> 2.txt
git add .
git commit --amend --no-edit
```

コミットメッセージを変更しない場合は `--no-edit` オプションを付けるとvimエディタが立ち上がらずに直前のコミットに変更を加えられます。

```shell-session
commit 7cf1083691390658cbaaf792309c67775f58be3e (HEAD -> main)
Author: ucan-lab <35098175+ucan-lab@users.noreply.github.com>
Date:   Thu Dec 15 23:52:15 2022 +0900

    second commit

diff --git a/2.txt b/2.txt
new file mode 100644
index 0000000..313108e
--- /dev/null
+++ b/2.txt
@@ -0,0 +1,3 @@
+second
+changed
+updated
```

`second commit` のコミットメッセージはそのままで内容が変更されていることを確認できたらOKです。

### 補足: 指定したコミットに変更を加える(--fixup)

`--amend` だと直前のコミットのみですが、 `--fixup` だと指定したコミットを変更できます。
`--fixup` オプションは Gitの[v1.7.4](https://raw.githubusercontent.com/git/git/master/Documentation/RelNotes/1.7.4.txt) から使用できます。

```
rm -rf .git; rm *.txt
git init; git branch -M main
echo 'first' > 1.txt; git add .; git commit -m "first commit"
echo 'second' > 2.txt; git add .; git commit -m "second commit"
echo 'third' > 3.txt; git add .; git commit -m "third commit"
```

```shell-session
echo 'changed' >> 2.txt
git add .
git commit --fixup=HEAD~
```

```shell-session
git log --oneline

8d58cd7 (HEAD -> main) fixup! second commit
963f532 third commit
9167c07 second commit
d9095bc first commit
```

`fixup!` のprefixが付いた修正コミットが追加されます。(ちなみにfixupするたびどんどん追記されます。)
このままでは普通にコミットされただけなので、rebase してコミットを整理する必要があります。

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

vimエディタが起動します。

```vim
pick 6c7c266 second commit
fixup 96068d0 fixup! second commit
pick 198dde2 third commit
```

コミットの順番が `second commit` の次に `fixup! second commit` が表示されています。
`:q` で閉じてOKです。

```shell-session
git log --oneline

4fe89aa (HEAD -> main) third commit
e3a1f92 second commit
bed8571 first commit
```

`fixup!` のコミットがなくなっていることを確認できます。

```shell-session
git show HEAD~

commit e3a1f927447e73c496572c84a9f7b34fd8edd5e2
Author: ucan-lab <35098175+ucan-lab@users.noreply.github.com>
Date:   Thu Dec 8 21:21:54 2022 +0900

    second commit

diff --git a/2.txt b/2.txt
new file mode 100644
index 0000000..e388a7a
--- /dev/null
+++ b/2.txt
@@ -0,0 +1,2 @@
+second
+changed
```

`second commit` の中身を確認して変更が反映されていればOKです。

### 補足: --fixup の amend, reword 指定

Gitの [v2.32.0](https://raw.githubusercontent.com/git/git/master/Documentation/RelNotes/2.32.0.txt) から使用できます。

```shell-session
rm -rf .git; rm *.txt
git init; git branch -M main
echo 'first' > 1.txt; git add .; git commit -m "first commit"
echo 'second' > 2.txt; git add .; git commit -m "second commit"
echo 'third' > 3.txt; git add .; git commit -m "third commit"
```

```shell-session
echo 'changed' >> 2.txt
git add .
git commit --fixup=amend:HEAD~
```

vimエディタが立ち上がります。
1行目は書き換えず、3行目以降のコミットメッセージを変更します。

```vim
amend! second commit

changed second commit
```

三行目を `changed second commit` に変更して `:wq` 保存して閉じます。

```shell-session
git log --oneline

dce29b5 (HEAD -> main) amend! second commit
3df8fd7 third commit
0254678 second commit
b624916 first commit
```

`amend!` のprefixが付いた修正コミットが追加されます。
rebase　してコミットをまとめます。

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

vimエディタが起動します。

```vim
pick 0254678 second commit
fixup -C dce29b5 amend! second commit
pick 3df8fd7 third commit
```

`:q` で閉じます。

```shell-session
git log --oneline

f313345 (HEAD -> main) third commit
cd46bbf changed second commit
b624916 first commit
```

```shell-session
git show HEAD~

commit cd46bbfedaee593324cc84d02ef957fae0ba7fde
Author: ucan-lab <35098175+ucan-lab@users.noreply.github.com>
Date:   Fri Dec 16 01:40:54 2022 +0900

    changed second commit

diff --git a/2.txt b/2.txt
new file mode 100644
index 0000000..e388a7a
--- /dev/null
+++ b/2.txt
@@ -0,0 +1,2 @@
+second
+changed
```

`changed second commit` にコミットメッセージが変わり、コミット内容も変更されていることを確認できればOKです。

## 補足: エディターを変更したい

https://qiita.com/ucan-lab/items/9b442e042988e2d7a35d

vimの矩形選択がどうしても苦手な人はvscodeをエディタにすることもできるのでお試しください。

## 参考

https://github.blog/2022-10-03-highlights-from-git-2-38/
https://www.praha-inc.com/lab/posts/commit-message
https://twitter.com/t_wada/status/904916106153828352?s=20

## さいごに

軽く補足を追加するつもりが、本題より長くなってしまいました。。
完全にやらかしました。(深夜3時)

おやすみなさい😪😪😪