【🔰初心者向け】Git入門 [revert, restore, stash]

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。今回の記事はGitコマンドの続きの記事となります。

前の記事はこちら👇

https://qiita.com/ikemura-ren/items/dcdf6dadb11c9a554e1a

![e87fb73d-aab4-4026-94d4-05ca95e97e75_720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/5aca4e01-c601-415e-bf27-d5f34d2bf0ec.png)


## `revert`コマンドについて
前回の記事で、`reset`周りの解説をしました。`revert`も`reset`に近いお仕事をしてくれるコマンドになります。ただ、明確に`reset`コマンドと違うところは、**取り消した**ということをコミットとして残してくれるところです。

#### `reset`の場合の動作は以下になります

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/3509ffd6-cfa4-4741-9834-30f82510e3f2.png)

:::note warn
`reset`の場合、コミット4はなくなります。
:::

#### `revert`の場合の動作は以下になります

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/06028b43-d418-4829-afb8-68f61c804335.png)

:::note info
パッとみてもよくわからないと思いますので、実際にコマンドを叩いて確認していきましょう。
:::

#### `revert`の使い方
今回の環境は、こちらの記事までで作成したリポジトリを使っております。

https://qiita.com/ikemura-ren/items/df4cfc534be61fa9c6ba

※ブランチはtest-branch1を利用しています。
では何かしらのファイルを追加してみましょう。
```Bash:ファイルを追加する
echo 'Hello Git!!' >> test3.txt
```

さて、`add`と`commit`でローカルの変更を確定します。

```Bash:使い方
git add .
git commit -m "test3.txtを作成し、Hello Gitを書き込んだ"
```

この状態でgit logを確認すると、以下のようになっているはずです。
![名称未設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/dc9ca056-2922-40f3-a531-77228c9fe8b5.jpeg)



さて、この状態で`revert`コマンドを使ってみましょう。

```Bash:使い方
git revert HEAD
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/029a65a1-01ea-47fd-b0d6-05fcc6305501.png)

`revert`コマンドを実行すると、上記のようにコミットメッセージを編集できるファイルが開かれます。

今回は少しメッセージを編集します。基本的にVimの操作になるので、`i`でインサートモードにしてから、`Revert "test3.txtを作成し、Hello Gitを書き込んだ"`の`""`で囲まれた部分を編集してみます。

`revertでtest3.txtを削除してやり直し`と書き直しました。書き込みが終わったら、`esc`キーを押して、`:wq`でファイルを閉じてください。

`git log`で確認してみましょう。

![名称未設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/1765ce9c-0d8b-41fb-ae31-7edb2ffa1721.jpeg)


:::note info
ついでに`ls`コマンドを実行して、test3.txtがどうなっているのかも確認してみましょう。
:::


新しいコミットが作られているのを確認しました。
`reset`と違うのは、元のtest3.txtを作成したコミットも残っているところです。ですので、そちらに`reset`で戻ることもできるし、再度`revert`をして元に戻すこともできます。

コミットメッセージなどを編集しない場合は、以下のオプションで可能です。

```Bash:使い方
git revert HEAD --no-edit
```

#### コミットIDを利用して、いくつか前の状態に戻すことも可能
revertはコミットIDを指定して戻すこともできます。今回はコミットID`b52e5dcce07541340ec0d1354b95120af4671fad`に戻ろうと思います。
```Bash:使い方
git revert b52e5d
```

こうすることで、リモートの状態と同じにすることができました。また最初からやり直しですね。

![名称未設定2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/a713fbf7-eab4-42e7-89f3-fa1b5dccc5ad.jpeg)

:::note info
とはいえ、`reset`と違って、やり直し前に戻ることができるのは安心だと思います。
:::

:::note alert
注意点として、`revert`はブランチがクリーンな状態（ステージングしていないファイル等がない）でしか実行できません。
:::



## `restore`コマンドについて
先ほどまではコミット単位のやり直しのお話でした。この`restore`コマンドは、作業ツリーの変更を取り消すためのコマンドです。ですので、**コミット前のファイルの変更を取り消すため**に使われます。

:::note alert
このコマンドは取り扱いに注意が必要です。作業した内容が失われます。
:::

ファイルを色々変更していると、このファイルの変更だけ元に戻したいな〜となることがあります。その際には`restore`コマンドを使っていきましょう。
では使い方をみていきます。
今回は、test3.txtに文字列を書き込んで、その変更をリセットしていきます。
```Bash:restoreの使い方
# ファイルに変更を加える
echo 'Test Restore!!' >> test3.txt 

# ファイルの中身を確認
cat test.3txt

# ステータスも確認
git status

# 変更を取り消す
git restore test3.txt
```

実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/36889e72-ce0a-4f35-b639-c5055740e4f0.png)

今回は1文しか追加していませんが、基本的にファイル単位での取り消しになりますので、注意が必要です。

#### ステージングを解除する
では次に間違ってaddをしてしまった場合です。ステージングされたファイルをステージから降ろすことが可能です。

```Bash:ステージングから解除する場合
# 再度ファイルを変更する
echo 'Test Restore!!' >> test3.txt 

# ステージングする
git add .

# ステータスを確認
git status

# ステージングを解除
git restore --staged test3.txt

# ステータスを確認
git status
```
実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/a9f34753-d39e-41a8-812e-11b10148e629.png)

:::note info
`reset --mixed`の場合は、ステージングされたファイルを全て解除できますが、個別に解除するなら`restore --staged`を使いましょう。
:::

#### 特定のコミットの状態まで戻す場合
コミットを元に、ファイルの状態を戻すこともできます。
```Bash:コミットIDを元にファイルの状態を戻す
git restore --source <コミットID> 戻したいファイル名
```

:::note alert
もちろん、そのコミットの状態をしっかり確認した上で実行してください。
:::

#### 全てなかったことにする
この使い方が一番危険ではあるのですが、ご紹介します。

```Bash:全部消しちゃえってコマンド
git restore .
```

:::note alert
慎重にファイルごと`restore`しないと、全て消えてしまうので大変です。完全に復元不可というわけではありません。（状況によっては復元可能）使う時は自己責任でお願いします。。
:::

## `stash`コマンドについて
次に`stash`コマンドについてご紹介します。
これは、現在の編集した変更部分を一時的に待避してくれるコマンドです。
早速使い方をみていきましょう。
```Bash:使い方
# 1文追加する
echo 'Test Stash!!' >> test3.txt  

# ファイルの中身を確認
cat test3.txt

# ステータスも確認
git status

# stashする
git stash

# ファイルの中身とステータスを確認
cat test3.txt
git status
```

実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/b39abc34-b1ec-4919-8452-4678d77e29a1.png)

さて、うまくコマンドが実行されているのであれば、変更はなくなっているはずです。一時待避させた状態であれば、違うブランチに移動したり、そのブランチがクリーンな状態で、新しいブランチを切ったりが可能になります。

#### 一時退避した変更部分を再度持ってくる
さて、`stash`はあくまで退避なので、復元することも可能です。
先ほどの実行後、退避した内容を確認してみましょう。

```Bash:stashのリストを確認
git stash list

# 実行結果
stash@{0}: WIP on test-branch1: 56fca9b test3.txtを作成し、Hello Gitを書き込んだ
```

##### **stash@{0}**
これは最新のstashを指しています。{}の中の数字で違う。
##### **WIP on test-branch1**
作業途中（Work In Progress）のstashで、test-branch1というブランチ上で作成
##### **56fca9b**
stashを作成した時点での最新コミットのハッシュ値
##### **test3.txtを作成し、Hello Gitを書き込んだ**
stash時に付けた説明文（メッセージ）。何もつけないと、最新のコミットメッセージになります。

#### 復元方法
退避した内容をファイルに復元していきましょう。
```Bash:復元方法
git stash pop
```

実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/b5e32899-8e44-409d-91a8-1e5d92063854.png)

:::note info
元に戻って、まだ`add`してないですよ！と言われています。ファイルの内容も元に戻っていますね。
:::



#### よく使う使い方
先ほどのシンプルな`stash`はあまり使わないので、以下によく使うやり方を残しておきます。

```Bash:使い方
git stash save "test3.txtの変更を一時的に退避"
```

:::note info
`save`を使うと、`stash`のメッセージを残すことができます。
:::

実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/e223d246-ae4d-4a04-813e-176f40e57546.png)

:::note info
メッセージもわかりやすくなっているのがわかりますね。
:::

##### 注意点
`stash`で同じファイルの変更点を別々に退避させた場合、復元の際にコンフリクトを起こす可能性が高まります。

```Bash:コンフリクトを起こす場合
# 退避させている状態でファイルを再度編集してstashさせる
echo 'Test Stash2!!' >> test3.txt  

git stash save "test3.txtの変更を一時的に退避2"

# 1回目は成功
git stash pop

git add .

# 2回目
git stash pop

Auto-merging test3.txt
CONFLICT (content): Merge conflict in test3.txt
On branch test-branch1
Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   test3.txt

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

ファイルの中身を見てみると、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/e3aa71a2-9650-454d-9997-022251cea902.png)

コンフリクトを解消させるため、2,4,6行を削除して、再度`add`をして終了です。
この例はかなり簡単なファイル内容でしたが、複雑なコードの中では取扱注意です。

#### `pop`と`apply`の違い
`git stash pop`を行うと、退避していた内容は消えてしまいます。退避した内容を消さずに、復元をしたい場合は`git stash apply`を使います。

```Bash:使い方
# 再度ファイルを編集
echo 'Test Stash3!!' >> test3.txt 

# 退避
git stash save "test3.txtにTest Stash3という文字列を追加した"

# 退避したstashを残しつつ復元
git stash apply

# stash listを確認
git stash list
```


実行結果👇
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/3b577fba-95c5-4fd9-bee5-a9e0c220461c.png)

#### 特定のファイルの変更分だけ`stash`したい場合
先ほどまでの例では、一つのファイルの変更点だけ扱っていましたが、複数ファイルの変更があった場合、かつ1つのファイルだけ指定して`stash`したい場合があります。

```Bash:一つのファイルだけstashしたい場合
git stash push -m "わかりやすいメッセージ" ファイル名
```
`-m`をつけないと、メッセージは残されず、自動で最新のコミットメッセージになりますのでご注意ください。

#### stashを消したい場合
stashを個別に消したい場合、専用のコマンドがあります。

```Bash:stashの消し方
git stash drop stash@{番号}
```

まとめて消したい場合は以下のコマンドでできます。
```Bash:stashをまとめて消す
git stash clear
```

:::note alert
取り扱い注意です。特に`clear`の方です。
:::

#### 差分を見てから復元したい場合
復元をする際に差分がみたい場合があると思います。
その際は、以下のコマンドで確認してみましょう。

```Bash:差分の確認
git stash show -p stash@{番号}
```

### `stash`コマンドのまとめ
`stash`コマンドはオプション系がかなりあるので、こちらにまとめを残しておきます。
| コマンド                         | 説明                         |
|---------------------------------|------------------------------|
| `git stash save "説明"`         | 説明つきで退避               |
| `git stash push -m "説明"`       | ファイル単位で説明つきで退避    |
| `git stash list`                | スタッシュ一覧を確認          |
| `git stash pop`                 | スタッシュを適用して、スタッシュは削除   |
| `git stash apply`               | スタッシュを適用するが、削除しない|
| `git stash drop stash@{番号}`   | 指定スタッシュを削除         |
| `git stash clear`               | 全スタッシュを削除           |
| `git stash show -p stash@{番号}` | 差分を詳細に表示（番号指定をしないと、最新のものと差分をみる）             |

## おわりに
ここまで読了、お疲れ様でした。
この辺りのコマンドはかなり大事ですが、結構覚えるの大変なんですよね。でもしっかりコマンドを叩いてみて、挙動を確認することが大事です。Gitを使わない開発現場なんて、ほぼないですからね。この辺りをしっかり押さえれば、初学者の方でも実際の現場で喰らいつけると思います！

それでは次回の記事はちょっとニッチなコマンドもご紹介しようと思います。