Gitで履歴の変更をしたいときの git rebase -i

# はじめに
コミットを重ねるうちに、ある部分の変更が複数のコミットに散らばってしまっていて、その途中の変更は必要ないってときにコミット履歴を変更してスッキリさせたかったので、`git rebase -i` を使って過去のコミットを変更する方法をまとめました。

（`-i` は **interactive**の意味で、対話的にrebaseを行う）


# コミットの並べ替え
## 1.  git rebase -i 

どこまでさかのぼるかを指定します
直近の3つのコミットを編集したいのであれば以下のようになる

* `$ git rebase -i HEAD~3` 

また、ハッシュ値でもOK（最新から数えて3つ前のコミットのハッシュ値）
`$ git log`で調べる


* `$ git rebase -i e3827efe81402f5f949c0ece246977145daf1d19` 

実行すると以下のようなエディタが開く

```
pick 0c86d25 Add first commit
pick 90faa14 Add second commit
pick e2c368f Add third commit

# Rebase e3827ef..e2c368f onto e3827ef
#
# 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
```


## 2. 並べ替える

```
pick 0c86d25 Add first commit
pick 90faa14 Add second commit
pick e2c368f Add third commit
```

↓ 1行目と2行目を入れ替える

```
pick 90faa14 Add second commit
pick 0c86d25 Add first commit
pick e2c368f Add third commit
```

保存してエディタを終了　`:wq`


### この時に使えるvimコマンド

* `yy`：ヤンク　　→カーソル行をコピー（その行は消えない）

* `p`：ペースト　　→カーソル行の下にコピーされた行を挿入

* `dd`：行の削除　　→カーソル行を削除


# コミットの統合
## 1.  git rebase -i 
上記と同様

## 2. pick を squash に書き換える

```
pick 0c86d25 Add first commit
pick 90faa14 Add second commit
pick e2c368f Add third commit
```

↓  2行目を1行目に統合したい場合、2行目のpick を squash に書き換える

```
pick 0c86d25 Add first commit
squash 90faa14 Add second commit
pick e2c368f Add third commit
```

保存してエディタを終了　`:wq`

### この時に使えるvimコマンド

* `de`：1単語の削除　　→pick の先頭にカーソルを合わせて実行


## 3. コミットメッセージの修正
Git  は2つのコミットを全て適用しエディタに戻る

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

Add first commit

# This is the 2nd commit message:

Add second commit

# Please enter the commit message for your changes. Lines starting
# with '#' will ignored, and an empty message aborts the commit.
...
```

↓　統合したコミットに新しいコミットメッセージをつける

```
# This is a combination of 2 commits.

Add first and second commits

# This is the 1st commit message:

Add first commit

# This is the 2nd commit message:

Add second commit

# Please enter the commit message for your changes. Lines starting
# with '#' will ignored, and an empty message aborts the commit.
...
```

このようにすると、`Add first commit`、`Add second commit` もコミットメッセージに含まれるので、必要なければ以下のように全て書き換える

```
Add first and second commits

# Please enter the commit message for your changes. Lines starting
# with '#' will ignored, and an empty message aborts the commit.
...
```

保存してエディタを終了　`:wq`

（修正を間違えた場合などは、以下の「**コミットメッセージの変更**」の手順に沿って修正）

### この時に使えるvimコマンド

* `[number]dd` ：複数行の削除


## 補足

2つ以上のコミットを統合する場合も、同様の手順で可能

```
pick 0c86d25 Add first commit
squash 90faa14 Add second commit
squash e2c368f Add third commit
```


# コミットメッセージの変更
## 直前のコミットの場合
	
1. `$ git commit --amend`

2. コミットメッセージの変更（エディタが開く）


## 過去のコミットの場合

1. `git rebase -i`（上記と同様）

2. 対象となるコミットの `pick`  を `edit`  に変更

3. あとは ”直前のコミットの場合” と同様



# コミットの分割
## 1.  git rebase -i
上記と同様

## 2. pick を edit に書き換える

```
pick 0c86d25 Add first commit
pick 90faa14 Add second commit and Update README
pick e2c368f Add third commit
```

↓  対象となるコミットの `pick`  を `edit`  に変更

```
pick 0c86d25 Add first commit
edit 90faa14 Add second commit and Update README
pick e2c368f Add third commit
```

保存してエディタを終了　`:wq`


## 3. コミットをリセット 

`$ git reset HEAD^`

コミット自体を取り消し、変更されたファイルをステージしていない状態にする
（追加変更のみなら実行しなくてよいが、コミットの分割の場合は必要）

## 4. 切り分けてコミット
一連をコミットを作り直す

```
$ git add README.md
$ git commit -m 'Update README'

$ git add rebase.rb
$ git commit -m 'Add second commit'
```


## 5. rebase --continue

`$ git rebase --continue`


# 参考サイト
* [Git - 歴史の書き換え](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E6%AD%B4%E5%8F%B2%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88)
* [過去のコミットを削除する方法 - Qiita](http://qiita.com/ykawakami/items/0d6826c529ad7c7b37dd)
* [git reset (--hard/--soft)ワーキングツリー、インデックス、HEADを使いこなす方法 - Qiita](http://qiita.com/shuntaro_tamura/items/db1aef9cf9d78db50ffe)

# 関連記事
* [コミット履歴の改善に役立つ git rebase -i 5つの使い方 - Qiita](http://qiita.com/kmt/items/42f7f5678d0fc1126d79)
* [２つのコミット履歴を１つに統合する - Qiita](http://qiita.com/TechMeetMeet/items/5db3d020b143b085697d)