【git rebase -i】したときのコマンドをすべて試してみた(p, r, e,s ,f ,x ,d)

# `git rebase -i` したときのコマンドをすべて試してみた(p, r, e,s ,f ,x ,d)

いわゆる `git rebase -i HEAD~~` とかしたときに出てくる下のほうに出てくるコメントアウトされているコマンドのことを今回まとめます。

```shell
pick 85b703f update 2
pick 4d9e3ec update 3

# Rebase 5d6b0f5..1fc7711 onto 5d6b0f5 (6 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
```

|  | 英語 | なんとなく適当な日本語訳 |
| :-: | :-: | :-: |
| p, pick | use commit | コミットを使う |
| r, reword | use commit, but edit the commit message | コミットを使うが、コミットメッセージを編集する |
| e, edit | use commit, but stop for amending | コミットを使うが、修正を止める |
| s, squash | use commit, but meld into previous commit | コミットを使うが、以前のコミットに混ぜる |
| f, fixup | like "squash", but discard this commit's log message | squashと似ているが、コミットメッセージは破棄する |
| x, exec | run command (the rest of the line) using shell | シェルを使用して、残りのコマンドを実行する |
| d, drop | remove commit | コミットを削除する |

## はじめに

これはgitの正確に記述しして、きちんと学んで形からはいる！！というタイプの記事ではないです。
実際に体験して、なんとなく理解してみようという記事です。

きちんとした記事は以下のようなのを参考にしてください。

- [サルでもわかるGit入門〜バージョン管理を使いこなそう〜【プロジェクト管理ツールBacklog】](https://backlog.com/ja/git-tutorial/)


## 実際に使ってみる

ディレクトリの作成とgitをスタートさせる。

```shell
$ mkdir git-work
$ cd git-work
$ git init
Initialized empty Git repository in /home/hirao/workspace/git-work/.git/
```

もし途中でgit操作を間違って最初に戻りたくなったら

```shell
$ rm -fr .git/
$ git init
# もうちょっといい方法ありますか…？
```

でやり直してください。

### ファイルの作成


```shell
echo 'First line' >> text.md 
git add .
git commit -m 'init'

echo 'line2' >> text.md && git commit -am 'update 2'
echo 'line3' >> text.md && git commit -am 'update 3'
echo 'line4' >> text.md && git commit -am 'update 4'
echo 'line5' >> text.md
echo 'line6' >> text.md && git commit -am 'update 6'
echo 'line7' >> text.md && git commit -am 'update 7'
echo 'line8' >> text.md && git commit -am 'update 8'
```

一気上をすべてターミナルに流し込む。

ファイルの中身を確認してみましょう。！！

```shell
yk:git-work yk$ cat text.md 
First line
line2
line3
line4
line5
line6
line7
line8
```

ちゃんとファイルの中身があることを確認します。

そしてGITのコミットのハッシュを `git log` で確認しておきましょう

```shell
$ git log --oneline

6e4cd32 (HEAD -> master) update 8
607b771 update 7
da03d43 update 6
bf8452b update 4
89b026f update 3
da1c070 update 2
581d53a init
```

### `s, squash = use commit, but meld into previous commit` を使ってみる

squashは `use commit, but meld into previous commit` というメッセージでしたね。私はコミットをまとめるときによく使ってます！。最初のコミットは `init` というコミットメッセージをつけたので、grepして見つけます。上のように `git log --oneline` で一番下のやつをコピペしても可能です。

```shell
$ git log --oneline | grep init

581d53a init
```

初回のコミットを取得する。次のコミット `update 2` から編集できる。

```shell
git rebase -i 581d53a
```

以下のように編集して。 `update2~3` をまとめてみましょう。

```shell
$ git rebase -i 581d53a

pick da1c070 update 2
s 89b026f update 3
pick bf8452b update 4
pick da03d43 update 6
pick 607b771 update 7
pick 6e4cd32 update 8
```

`update2~3` は `s` オプションでの編集なので、コミットメッセージの編集ができます。以下のような感じ。

```shell
$ git rebase -i 581d53a

hint: Waiting for your editor to close the file... 
# This is a combination of 2 commits.
# This is the 1st commit message:

update 2

# This is the commit message #2:

update 3
```

これを

```vim
update2 and update3
```

へ変更。

```shell
$ git log --oneline  

0317cc1 (HEAD -> master) update 8
a1526af update 7
27bce0d update 6
764c9ea update 4
3e13197 update2 and update3
581d53a init
```


となりました。

### `e, edit = use commit, but stop for amending` を使ってみる

間違って `update 5` というコミットを作るつもりだったのに、 `update6` にまとまっています。編集しましょう。

```shell
$  git log --oneline

0317cc1 (HEAD -> master) update 8
a1526af update 7
27bce0d update 6
764c9ea update 4
3e13197 update2 and update3
581d53a init
```

また init コミットまでのrebaseをしましょう。

```shell
git rebase -i 581d53a
```

出てきた画面で以下のように `update 6` の `pick` を `e` に変更して、以下のようにする。

```vim
pick 3e13197 update2 and update3
pick 764c9ea update 4
e 27bce0d update 6
pick a1526af update 7
pick 0317cc1 update 8
```

以下のような感じになって、rebaseがストップします。

```shell
$ git rebase -i 581d53a

Stopped at 27bce0d...  update 6
You can amend the commit now, with

  git commit --amend 

Once you are satisfied with your changes, run

  git rebase --continue
```

最後のコミットを確認します。これを編集してコミットするか、リセットしてやりなおすか…

```shell
$ g show 

commit 27bce0d8e8e4c9ef38ae702d7259b72ee775e6a5 (HEAD)
Author: Yuki <author@example.com>
Date:   Mon Sep 16 21:41:29 2019 +0900

    update 6

diff --git a/text.md b/text.md
index a5e67f7..d3a7cc2 100644
--- a/text.md
+++ b/text.md
@@ -2,3 +2,5 @@ First line
 line2
 line3
 line4
+line5
+line6
```

一個前のコミットを削除しましょう。！！ `line5` と `line6` という行を追加したコミットです。

```shell
$ git reset --hard HEAD~
HEAD is now at 764c9ea update 4

$ git log --oneline
764c9ea (HEAD) update 4
3e13197 update2 and update3
581d53a init
```

この時、 `update 4` までしか表示してないのは、rebaseの途中で動作を止めるオプション `e/edit` を使ったからです。 
コミット削除したら、一行ずつ追加してコミットしていきます。

```shell
$ echo 'line5' >> text.md && git commit -am 'update 5'
$ echo 'line6' >> text.md && git commit -am 'update 6'
```

ちゃんとコミットされているか、確認します。

```shell
$ git log --oneline
b9e284b (HEAD) update 6
fd9fe8c update 5
764c9ea update 4
3e13197 update2 and update3
581d53a init
```

大丈夫そうなら `git rebase --continue` して続けます。

```shell
$ git log --oneline

818cfad (HEAD -> master) update 8
b9fffe7 update 7
b9e284b update 6
fd9fe8c update 5
764c9ea update 4
3e13197 update2 and update3
581d53a init
```

これで5と6を分割できましたね。
ただしeオプションは、下手にやると `update 7` 以降のコミットによってコンフリクトが発生するので、置きをつけてください。

### `f, fixup = like "squash", but discard this commit's log message` を使ってみる

メッセージの編集なしの `s` オプションと同じです。

```shell
$ git rebase -i 581d53a

pick 3e13197 update2 and update3
f 764c9ea update 4
f fd9fe8c update 5
f b9e284b update 6
f b9fffe7 update 7
pick 818cfad update 8
```

と最後のコミット以外を`f` オプションをつけて `update2 and update3` にすべて統合してみましょう！！！
コミットメッセージが確認されずにコミットされましたね。

```shell
$ git log --oneline

4b3bee7 (HEAD -> master) update 8
0cd592f update2 and update3
581d53a init
```



コミット `update6~8` がまとまりましたが、コミットメッセージは何も聞かれませんでした。これは `f` コマンドはコミットメッセージはそのままコミットをまとめるものだからです。

### `r, reword = use commit, but edit the commit message` を使ってみよう

`r` を使ってコミットのメッセージを変更しよう。

```shell
$ git rebase -i 581d53a

pick 0cd592f update2 and update3
r 3c72cf0 update 8
```

するとvimが立ち上がるので

```vim
last commit 
```

と入力して閉じるとコミットメッセージが変更されています。

```shell
$ git log --oneline

1826743 (HEAD -> master) last commit
0cd592f update2 and update3
581d53a init
```

実は一番最後のコミットメッセージの変更でしたら

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

で大丈夫です。

```vim
last commit (2)
```

に編集してみましょう。

```shell
$ git log --oneline
89a9f1c (HEAD -> master) last commit (2)
0cd592f update2 and update3
581d53a init
```

### `d, drop = remove commit` を使ってみよう

実は最後のコミットは使わないコミットでした。的な場合は `d` オプションで消しましょう。

```shell
$ git rebase -i 581d53a

pick 0cd592f update2 and update3
d 89a9f1c last commit (2)
```

最後のコミットを消せたと思います。

```shell
$ git log --oneline
0cd592f (HEAD -> master) update2 and update3
581d53a init

$ cat text.md
First line
line2
line3
line4
line5
line6
line7
```

line8が消えました。

### `p, pick = use commit` を使ってみる

今まで何回も使っていましたね。何もしないのが `pick` みたいです。

### `x, exec = run command (the rest of the line) using shell` を使ってみよう

`x` コマンドはすごくいろんなことができるので調べてみると楽しいかもしれません。今回は先人たちの記事の紹介のみにとどめておきます。理由は、私がこれを使わなければいけないシチュエーションを思いつかなかったからです。

以下の記事では `exec git stash pop; git commit -a --amend -C HEAD` や `exec ruby -e '$<.read == "Alfa\nBravo\n" ? exit(0) : exit(1)' < example.txt` などが紹介されており、gitの他のコマンドを実行したり、rubyを実行したり、さまざまな使用例がありそうでした。

- [Git のコミット履歴を大胆に書き換えるなら git rebase -i がオススメ - yu8mada](https://yu8mada.com/2018/08/23/if-you-drastically-rewrite-git-s-commit-history-git-rebase-i-is-recommended/#content-1-8)
- [git-rebaseのexecを使ってstashした内容を履歴に埋め込む
](https://qiita.com/yuku_t/items/fed530acb97385ecbeee)

## 終わりに

`git rebase -i` のときのオプションはいかがだったでしょうか！

ドキュメントを読んで知っていたけど、実際に使ったのは初めて、というのもあるかもしれません。

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




.