過去のコミットを削除する方法

# はじめに
Git初心者の私が使用したコマンドの中でも、過去のコミットの削除を行う方法をご紹介します。

# 前提
ディレクトリ構成とコミット履歴下記のとおりです。
これらのコミットに対して操作をしていきます。

```bash
$ tree .
.
├── first.txt
├── second.txt
├── test.txt
└── third.txt
```

```bash
$ git log --name-status
commit 1e0676bc80d26143c972aa9b08ff4940a10e22e8
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:42:35 2015 +0900

    Added third.txt

A       third.txt

commit 5e6448ddb2c4ecd12ec24175e58c49582836b45a
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:41:59 2015 +0900

    Added second.txt

A       second.txt

commit 64ca8df0c49f43ea9149e499c62d636ab9bcdd26
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:41:29 2015 +0900

    Added first.txt

A       first.txt

commit 1c14c4654f4ebd4aa88d75726bcfecb2e87a7f0b
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:38:44 2015 +0900

    Added test.txt

A       test.txt
```

# コミットのロールバックを行う方法

あるコミットまで戻す方法です。
今回はsecond.txt追加のコミットの直後まで戻ります。
なのでコミットはもちろん、third.txtが存在しない状態が目標になります。

## 使用するコマンド

`git reset [option] [commit]`
オプションでは修正の範囲を指定します。

## 使用例

* [option]： 直前のコミットの内容をワーキングツリーから削除するため、 `--hard` を指定
* [commit]： 2つ前のコミットまで戻るので、 `HARD^` もしくは コミットのハッシュ値を指定


```bash
# HEAD^を指定する場合
$　git reset --hard HEAD^
HEAD is now at 5e6448d Added second.txt
```

```bash
# コミットのハッシュ値を指定する場合
$　git reset --hard 5e6448ddb2c4ecd12ec24175e58c49582836b45a
HEAD is now at 5e6448d Added second.txt
```

すると下記のように、コミット履歴からthird.txtを追加したコミットが消え、
最新のコミットがsecond.txtを追加したコミットになったことがわかります。

```bash
$ git log --name-status
commit 5e6448ddb2c4ecd12ec24175e58c49582836b45a
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:41:59 2015 +0900

    Added second.txt

A       second.txt

commit 64ca8df0c49f43ea9149e499c62d636ab9bcdd26
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:41:29 2015 +0900

    Added first.txt

A       first.txt

commit 1c14c4654f4ebd4aa88d75726bcfecb2e87a7f0b
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:38:44 2015 +0900

    Added test.txt

A       test.txt
```

下記からファイルが削除されていることも確認できます。

```
$ tree .
.
├── first.txt
├── second.txt
└── test.txt
```

これで無事コミットのロールバックを行うことができました。

上記ではコミットとthird.txt自体を削除するためにoptionに `--hard` を指定しました。
`git reset` で他のoptionを指定すると下記のような結果になります。

| option     | 削除対象        | 備考 |
|:-----------|:------------|:------------|
| --hard     | コミット + そのコミットでの変更内容 |  |
| --mixed    | コミット | `git add` されていない(インデックスに登録されていない) |
| --soft     | コミット | `git add` されていない(インデックスに登録されている) |
| 指定なし    | `--soft` を指定したときと同様 |  |

# 過去のコミットを削除する方法

直前のコミットではなく、過去のコミットを削除する方法です。
今回は2つ前のsecond.txtのコミットを削除します。
なので、コミットが削除され、second.txtが存在しない状態が目標になります。

## 使用するコマンド

`git rebase -i [commit]`

## 使用例

* [commit]： 2つ前のコミットよりも前のコミットを指定します。

```
$ git rebase -i 1c14c4654f4ebd4aa88d75726bcfecb2e87a7f0b
```

上記を実行するとテキストエディタが開きます。
そこで、今回削除したいsecond.txt追加のコミットの行を削除し保存します。

```bash
pick 64ca8df Added first.txt                                                    
pick 5e6448d Added second.txt <-この行を削除                                                   
pick 1e0676b Added third.txt                                                    
                                                                                
# Rebase 1c14c46..1e0676b onto 1c14c46                                          
#                                                                               
# 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                     
#                                                                               
# 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
```

それではコミット履歴からsecond.txt追加のコミットが削除されているか確認します。

```bash
$ git log --name-status
commit eb30f92d9fadfc1127001ef9fd4ff86eab4c27a8
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:42:35 2015 +0900

    Added third.txt

A       third.txt

commit 64ca8df0c49f43ea9149e499c62d636ab9bcdd26
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:41:29 2015 +0900

    Added first.txt

A       first.txt

commit 1c14c4654f4ebd4aa88d75726bcfecb2e87a7f0b
Author: Your Name <you@example.com>
Date:   Wed Dec 16 10:38:44 2015 +0900

    Added test.txt

A       test.txt
```

コミット履歴からは削除されていることが確認できました。
では次にファイル自体も削除されているかを確認します。

```bash
$ tree .
.
├── first.txt
├── test.txt
└── third.txt
```

これでコミット、ファイルともに削除されていることが確認できました。

# 参考サイト
[[git reset (--hard/--soft)]ワーキングツリー - Qiita](http://qiita.com/shuntaro_tamura/items/db1aef9cf9d78db50ffe)