git revertで注意すべきこと



Gitの取り消し操作としてresetとrevertはよく使いますが、revert操作で注意すべきことがあったのでまとめました。注意すべきことというのは、revertを使うとコミットが置いていかれるケースがあるというものです。

## resetとrevertって？
以前まとめた記事があるので[こちら](http://tech.aainc.co.jp/archives/4851)で確認してみてください。

## 事前準備
確認用に次の構成のブランチを用意しておきます。

- masterでA、Bをコミット
- Bからdevelpブランチを切りCDをコミット
- masterに戻りE、Fをコミット

またこの準備段階のリポジトリは[こちら](https://github.com/taisa007/git-revert-recipe)へあげてあります。

```
※ 下から上へとみていきます
* c2a619e 2015-06-18 sato.masaki (HEAD -> master, origin/master) F
* f28b9dc 2015-06-18 sato.masaki E
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

## resetの使い所
revertの注意点を確認する前に、resetの使い所について確認していきます。gitの取り消し操作において、巻き戻しであるresetコマンドが使えるのあればrevertではなくresetを使います。

では、masterにdevelopをマージした直後にマージコミットを巻き戻すという動作を確認してみます。

```
git checkout master
# masterにマージ
git merge develop
```

```
*   896c2e5 2015-06-18 sato.masaki (HEAD -> master) Merge branch 'develop' ← masterにマージしたコミット
|\
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
* | c2a619e 2015-06-18 sato.masaki (origin/master) F
* | f28b9dc 2015-06-18 sato.masaki E
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

この場合、masterが戻りたいのはFのコミットなのでFのハッシュを指定します（オプションはお好みで）

```
git reset --hard c2a619e ← Fのハッシュを指定
```

マージ前に戻りました。

```
* c2a619e 2015-06-18 sato.masaki (HEAD -> master, origin/master) F
* f28b9dc 2015-06-18 sato.masaki E
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

ただし次のようにマージ後に別のコミットがある場合は指定のコミットまで巻き戻せないのでrevertします。

## revertの使い所
最初のリポジトリのdevelopをマージした後から確認してみます。

```
*   31fb390 2015-06-18 sato.masaki (HEAD -> master) Merge branch 'develop' ← developをマージ
|\
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
* | c2a619e 2015-06-18 sato.masaki (origin/master) F
* | f28b9dc 2015-06-18 sato.masaki E
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

マージ後にmasterへGとHのコミットを追加します。

```
* f55e81b 2015-06-18 sato.masaki (HEAD -> master) H ← コミット追加
* 927cb80 2015-06-18 sato.masaki G ← コミット追加
*   31fb390 2015-06-18 sato.masaki Merge branch 'develop' ← developをマージ
|\
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
* | c2a619e 2015-06-18 sato.masaki (origin/master) F
* | f28b9dc 2015-06-18 sato.masaki E
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

この時点でdevelopのマージコミットを取り除きたい場合マージコミットをrevertします。

```
git checkout master
git revert -m 1 31fb390
```

```
* e854fbd 2015-06-18 sato.masaki (HEAD -> master) Revert "Merge branch 'develop'"  ← revertコミット
* f55e81b 2015-06-18 sato.masaki H
* 927cb80 2015-06-18 sato.masaki G
*   31fb390 2015-06-18 sato.masaki Merge branch 'develop' ← このコミットをrevert
|\
| * 96761c4 2015-06-18 sato.masaki (origin/develop, develop) D
| * d1fb102 2015-06-18 sato.masaki C
* | c2a619e 2015-06-18 sato.masaki (origin/master) F
* | f28b9dc 2015-06-18 sato.masaki E
|/
* 6c9045f 2015-06-18 sato.masaki B
* 9e5a5ec 2015-06-18 sato.masaki A
```

マージコミットを打ち消しました。

この次の作業において**revertの注意すべきこと**があります。

それは、revertを実行したことでコミットが巻き戻ったと勘違いしてしまう場合です。revertはコミットの打ち消しの為、コミットがすべて破棄された状態でコミットが進行します。

その為revert後に作業ブランチ（この場合develop）で続けて不具合解消するなどの操作をするとコミットがおいていかれる状況が発生します。更にそれに気付きにくい為、不具合が起きてから発覚してしまうケースもあります。

ではどういうことかrevert後から確認してみます。

developブランチで続けてCの編集とIの追加をします。

```
git checkout develop
# Cを編集しIを追加しコミット
git checkout master
git merge develop
# Cは同時に編集しているのでコンフリクトが起きますが修正版を適用していきます。
git add .
git commit
```

これで修正も終わり一段落というところなのですが、ファイル一覧をみてみるとDがなくなっています。revertしたmasterブランチの続きから作業しなかった為、developのコミットがなくなりました。

```
-rw-r--r--  1 17:15 A
-rw-r--r--  1 17:15 B
-rw-r--r--  1 18:30 C ← Dがない
-rw-r--r--  1 18:30 E ← Dがない
-rw-r--r--  1 18:30 F
-rw-r--r--  1 18:30 G
-rw-r--r--  1 18:30 H
-rw-r--r--  1 18:30 I
```

## どうすればよかったのか
- masterから新しいブランチを切る（developにmasterをマージしてもよい）
- 続きから編集したい場合はrevertのrevertをする

```
git checkout master
git checkout -b topic-branch
git revert e854fbd51cbe753d56a9d44ae1bd68da67477afa ← revertのrevert
# Cを編集しIを追加してコミット
```

これでOK

```
-rw-r--r--  1 17:15 A
-rw-r--r--  1 17:15 B
-rw-r--r--  1 18:30 C ← 不具合解消箇所
-rw-r--r--  1 18:30 D ← Dがある
-rw-r--r--  1 18:30 E
-rw-r--r--  1 18:30 F
-rw-r--r--  1 18:30 G
-rw-r--r--  1 18:30 H
-rw-r--r--  1 18:30 I ← 不具合解消箇所
```

## まとめ
* resetは巻き戻しでrevertはコミットの打ち消し
* revertした場合は新しくブランチを切りなおして作業する
* revertした内容を使いたい場合はrevertをrevertをする