git restore と git reset の違いを整理してみた

## はじめに
Gitの学習をしていて`git restore`と`git reset`の使い分けが気になったので調べてみました。

## 大まかな違い
- `git restore`：作業内容の巻き戻しに使う。ステージングやワークツリーの状態を安全に戻したいときに使う。  
→対象のファイルやディレクトリを引数に指定する。  
　例：`git restore index.html` や `git restore .`    
→ オプションで `--source=コミットID` を指定すれば  
　過去のコミット時点の状態に戻すことも可能。  
　例：`git restore --source=HEAD^ .`（1つ前のコミットの状態に戻す）  
　　　`git restore -s HEAD^ .`（短縮形）  

- `git reset`：履歴の巻き戻しに使う。HEADを移動させて「このコミットからやり直したい」ときに使う。  
   →巻き戻したい過去のコミットIDを引数に指定する。  
　例：`git reset --hard abc1234` や `git reset HEAD^`


## 使用例
| やりたいこと                                                                                                                                     | コマンド                                | ワークツリー     | ステージ（index） | コミット履歴（HEAD）         |
|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|------------------|-------------------|------------------------------|
| 編集内容を破棄する                                                                                                                               | git restore ファイル名                  | 変更破棄         | 影響なし          | 影響なし                     |
| addを取り消す                                                                                                                                    | git restore --staged ファイル名         | 影響なし         | 解除              | 影響なし                     |
| 編集もaddも両方取り消す                                                                                                                          | git restore --staged . && git restore . | 変更破棄         | 解除              | 影響なし                     |
| コミットを取り消す（履歴ごと）                                                                                                                   | git reset --hard コミットID             | 指定の状態に戻る | 指定の状態に戻る  | 指定した位置にHEADを移動する |
| コミットは戻すが作業状態は残す（指定したコミット以降の変更内容がすべてステージされた状態になる。直近の2つのコミットを1つにまとめ直したいとき等） | git reset --soft コミットID             | 保持される       | 保持される        | 指定した位置にHEADを移動する |
| コミットとaddを戻すが作業状態は残す（コミットしたけどやっぱり編集内容は見直したいとき等）                                                       | git reset --mixed コミットID            | 保持される       | 指定の状態に戻る  | 指定した位置にHEADを移動する |

※ `git reset` でオプション（`--soft` / `--mixed` / `--hard`）を指定しなかった場合デフォルトは `--mixed` になる。

## 捕捉：直前のコミットを修正したいときは`--amend`
コミット後に「メッセージを修正したい」「ファイルを追加し忘れた」といった軽い修正には、`git reset` よりも `--amend` を使う方が簡単。

```
git add 修正したファイル
git commit --amend
```

## 注意：`git reset`はチーム開発では基本NG
`git reset`や`--amend`は便利だが履歴を書き換えるコマンドなのですでに共有されたコミットに対して使うとトラブルの元になる。
自分がpushしたブランチをreset --hardで巻き戻して上書きpushすると、他の人の作業とズレが生まれたり履歴が壊れることがある。

万が一reset操作をミスった場合、直後であれば`git reflog`で直前のコミットIDを確認し復元できる。  
```
git reflog # 直前のコミットIDを確認
git reset --hard <戻したいコミットID>
```

## `git revert`も含めた3者の違い
`git reset`と似た名前の`git revert`というコマンドもあるが、こちらは「過去のコミットを打ち消す新しいコミットを作る」操作。  
履歴を書き換えないので安全な巻き戻し手段としてチーム開発で使われる。 

| コマンド | 主な目的                         | 対象         | 影響する領域                 | 履歴の扱い             | よく使う場面                           |
|----------|----------------------------------|--------------|------------------------------|------------------------|----------------------------------------|
| restore  | ファイルの状態を戻す             | ファイル単位 | ワークツリー・ステージ       | 履歴に影響しない       | 編集取り消し／add取り消し              |
| reset    | コミット履歴を巻き戻す           | コミット単位 | HEAD・ステージ・ワークツリー | 過去に戻る（履歴変更） | コミットのやり直し／修正したい         |
| revert   | 元に戻す「新しいコミット」を作る | コミット単位 | HEADに新たな履歴を追加       | 履歴はそのまま         | 共同開発中のバグ修正など安全な取り消し |

## おまけ：引数に使われる記号など
- HEAD系

| 記法   | 意味                                          | 例                        |
|--------|-----------------------------------------------|---------------------------|
| HEAD   | 現在のブランチが指している最新コミット        | git reset --soft HEAD     |
| HEAD^  | 一つ前のコミット                              | git reset --hard HEAD^    |
| HEAD^^ | 二つ前のコミット                              | git reset --hard HEAD^^   |
| HEAD^2 | マージコミットの2番目の親（マージしてきた側） | git show HEAD^2           |
| HEAD~  | 一つ前のコミット（HEAD~1 の省略形）           | git reset --hard HEAD~    |
| HEAD~N | N個前のコミット（HEAD~2なら二つ前）           | git reset --mixied HEAD~2 |

※^と~の違い  
^は親コミットを辿るが、マージコミットのとき分岐ができる。  
~は直線的にN個前と数える。

- 「.」の意味

| 記号 | 意味                                     | よくつかうコマンド例          |
|------|------------------------------------------|-------------------------------|
| .    | カレントディレクトリ以下の全てのファイルとディレクトリ | git add .／git restore . など |