【図解】初心者にもわかる git checkout / revert / restore / reset の違い

# ◼️ はじめに

こんにちは．

突然ですが，`git` 使いこなせていますか？

「とりあえず commit して履歴を積み重ねているだけ…」という方も多いのではないでしょうか．

Git には，過去のコミットを「参照」したり「巻き戻し」たりするための便利なコマンドがいくつか用意されています．しかし，それぞれの動作や違いが少しわかりづらく，混乱しやすいポイントでもあります．

そこで今回は，`revert`，`checkout`，`restore`，`reset` の4つのコマンドについて，**図を用いながら視覚的に整理し，ざっくりと概要をつかめる**ように解説してみたいと思います！

:::note warn

私自身も最近学び始めたばかりのため，一部に誤りや不正確な説明が含まれている可能性があります．

本記事では「ざっくり理解する」ことを目的としており，細かい仕組み（ステージングエリアやワークツリーなど）の説明は省略しています．
:::



# ◼️ 4つのコマンドのイメージ

## ◻️ `git checkout`

まずは，`git checkout` コマンドです．

一言で言えば，「**過去のコミットの状態に一時的に切り替える**」ために使います．

（※ 以前はブランチの切り替えやファイル単位の操作などにも使われていましたが、現在は `git switch` や `git restore` にその役割が分割されました）

`checkout` は過去のコミットを「編集する」のではなく，「どんな状態だったか確認したい」ときに使用するコマンドです．

下の図を使ってもう少し具体的に説明します．

![git-ckeckout2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051745/f6999e1d-8650-4d4b-859c-2a4fea07f299.png)


上段が `checkout` 前（before），下段が `checkout` 後（after）の状態です．

例えば現在，最新コミット D にいるとします．そのとき，2つ前のコミット B の状態を確認したくなったとしましょう．

その場合，次のように `checkout` コマンドを使うと…

```bash
$ git checkout B  # BはコミットID
```

コミット B の状態に切り替わります．このとき，**HEAD** も B を指すようになります（図では赤色で表現）．

元いた D に戻りたくなった場合は，以下のコマンドで直前の状態に戻せます：

```bash
$ git checkout -
```

## ◻️ `git revert`

次は，`git revert` コマンドです．

簡単にいうと，「特定のコミットの変更内容を**打ち消す**ような**新しいコミット**を作成する」コマンドです．

下の図を使って説明します．

![スライド2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051745/2f86780c-f12c-4d42-8410-eb4c601bb8a1.png)

図の上段（before）では，現在のHEADはコミットDを指しています．

この状態で，**過去のコミットCの内容を取り消したい**としましょう．

このときに `git revert` を使うと，**Dの後ろに「Cの変更を打ち消す」新たなコミット**（ここでは "revert of C"）が作成されます．

つまり，Dの内容はそのままで，Cで行った変更のみが取り消されます．

具体例を使って説明します．

1. Bの変更：`foo`を追加
    
    ```diff
    + foo
    ```
    
2. Cの変更：`bar`を追加
    
    ```diff
      foo
    + bar
    ```
    
3. Dの変更：`hoge`を追加
    
    ```diff
      foo
      bar
    + hoge
    ```
    
4. Dの変更（ `hoge` ）は残したままで，Cの変更（ `bar` ）を消したい場合：
    
    ```bash
    $ git revert C  # CはコミットID
    ```
    
    すると以下のような状態になります：
    
    ```diff
      foo
    - bar
      hoge
    ```
    

こんな感じです．

## ◻️ `git restore`

次は，`git restore` です．

一言で言うと，「**コミット履歴を壊さずに、過去のある時点の状態に戻す**」ためのコマンドです．

図を使って説明します．

![git-restore2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051745/a81b3389-0ce4-40c2-988e-2bd94d90d10a.png)

図の上段（before）では，現在のHEADはDを指しています．

ここで「やっぱりCの状態に戻したい」と思ったとしましょう．ただし，**Dのコミットは削除せずにログとして残したい**という状況です．

そこで `git restore` を使うと，**現在のブランチやHEADの位置はそのままで，中身をCの状態に戻す**ことができます．

（`restore`後は，まだコミットされてないのでHEADはDのままで，中身はCを複製してきた状態になっています．）

## ◻️ `git reset`

最後は，`git reset` コマンドです．

このコマンドは，「**過去のコミット状態に巻き戻す**」ためのものです．

実際には完全に消えるわけではありませんが，**参照されなくなり復元が難しくなる**という点で注意が必要です．

図を使って説明します．

![git-reset2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051745/59bed4ca-cd3c-45d6-9c25-c8231e51846f.png)

図の上段（before）では、コミットが A → B → C → D と続いており，現在のHEADは D を指しています．

ここで「やっぱりCの状態に戻したい」となったとき，`git reset` を使うと **ブランチの先端（HEAD）そのものをCに移動**させることができます．

`restore` も`reset` も「過去の状態に戻す」という点では似ていますが，`reset` は **ブランチの先端（HEAD）を過去のコミットに戻す**ため，**以降の履歴（例：D）では見た目上削除されてしまいます．**

※Git内部には残っているものの，通常のログでは見えなくなり，復元が難しくなります．

# ◼️ 終わりに

ここまで，Gitで過去の状態に戻るための4つのコマンドについて，図を用いてご紹介しました．

それぞれの役割や違いをイメージできるようになっていれば幸いです！

今後は，今回省略した「ステージング領域」や「コミット状態」など，より詳しい内容にも触れていく予定です．

それぞれのコマンドが内部でどう作用しているのかにも，少しずつ踏み込んでいければと思います！