Gitで状態の復元と取消、削除する方法とその違い(git checkout, git reset, git revert, git rm)

# この記事を書くきっかけ
Gitを使っていて、ファイルを削除したいと思うことがありましたが、「まあそのままにしていても問題ないからいいや。間違って消しちゃったら怖いし。」と思って手をつけていませんでした。今回、Gitについて勉強したおかげで狙い通りの操作ができたので、記事にしてみました。
当然ですが、どの操作もちゃんと違いがあるので、その違いに自信がない方は是非参考にしてみてください。

# 状態の復元 (git checkout, git reset, git revert)
最新コミットまで状態を戻したいと思ったり、ステージングエリアに仮登録したものをやっぱり取り消したいと思ったり、そんなことありませんか。ファイルの変更を取り消して、以前の状態を復元させる方法を勉強します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642333/7192ce6c-52fc-15ff-5ea4-49f4fc31adc3.png)

| コマンド | 内容 |
|:-|:-|
|  git checkout -- <ファイルパス名> |  ワーキングディレクトリへの変更を取り消す。直前のコミットの状態に戻る。|
|  git reset　<ファイルパス名> |  ステージングエリアに追加した変更をワーキングディレクトリへ戻す |
|  git revert HEAD　|最新のコミットを打ち消し、前の状態に戻す|

## git checkoutとは

**ファイルの内容の変更を元に戻すコマンド**

`git checkout -- <file-path>`
このコマンドは、ステージングエリアやワーキングディレクトリの指定ファイルの変更を直前のコミットの状態に戻すものです。ファイルをいろいろ変更しちゃったけど、やっぱり前コミットした状態まできれいに戻したい！というときは`git checkout -- <file-path>`コマンドで元に戻せます。
`git checkout --　<〇〇>`のように、パラメーターにブランチ名ではなく、ハイフン2つを指定すると、「直前のコミット状態に戻す」という動きをします。


### git checkoutのその他の機能

**ブランチの切り替え**
`git checkout <branch-name>`

**新しいブランチの作成**
`git checkout -b　<new_branch_name>`

**特定のコミットにチェックアウト**
`git checkout <commit-hash>`
このコマンドは、特定のコミットに対して作業ディレクトリを切り替える操作です。この操作により、そのコミット時点のプロジェクト状態に戻すことができます。
主に、以下の用途で使われます。

- 過去の状態を確認するため
    - 特定のバグがどの時点で発生したかを調査する
    - 特定の機能が追加されたタイミングを確認する
- 過去の状態を基に作業を行うため：
    - 過去のバージョンを基に新しいブランチを作成する
    - 特定のバージョンを基にした検証やテストを行う

## git reset とは
ファイルをステージングエリアに仮登録したあと、その操作を取り消すコマンドです。 
`git reset <file>`

`git add .` コマンドでワーキングディレクトリからステージングエリアへ登録したファイルを、そのままステージングエリアからワーキングディレクトリに戻す感じです。ワーキングディレクトリ内のファイルの中身を取り消すわけではないので、変更した内容自体はそのまま残ります。



## git revertとは
**特定のコミットによる変更を打ち消す新しいコミットを作成するコマンド**
`git revert HEAD`

- 最新の変更を元に戻す
`git revert HEAD` を使用すると、最新のコミットを打ち消す新しいコミットが作成されます。これにより、最新の変更が取り消されますが、コミット履歴は保持されます。

- 履歴の保全
`git revert` はコミット履歴を保つ方法です。元のコミットを削除せず、変更を打ち消す新しいコミットを作成するため、履歴が改ざんされません。コミットを削除してしまうと、後から見直したときに空白のコミットがあるため混乱してしまいます。その点、`git revert` は履歴の一貫性を保証してくれます。

- 問題のあるコミットの修正
バグや問題を引き起こしたコミットがある場合、そのコミットを打ち消すことで問題を修正できます。これにより、問題の原因となる変更を簡単に取り除くことができます。

```
# 最新のコミットを打ち消す新しいコミット
commit b9cd081
Author: Your Name <you@example.com>
Date:   Thu Jun 13 14:25:34 2024 +0900

    Revert "new file"　 

    This reverts commit 86bb32e.

#　最新のコミット
commit 86bb32e
Author: Your Name <you@example.com>
Date:   Thu Jun 13 14:22:34 2024 +0900

    new file

```

# ファイルを削除する (git rm)
取消とは違い、ファイルを削除するには少し注意が必要です。

gitの管理下にあるファイルはエクスプローラーなどでただ削除するだけでは不十分だからです。削除と同時に、「削除した状態」をコミットしなければなりません。
| コマンド | 内容 |
|:-|:-|
| git rm "ファイルパス" |  Git管理下のファイルを削除する　|
| git rm -r "ディレクトリパス"|  Git管理下のディレクトリを削除する　|

## git rm とは
`git rm`コマンドとは、ワーキングディレクトリからファイルやディレクトリを削除し、その削除した状態をステージングエリアに登録するコマンドです。`git rm`コマンドのあとにコミットをすると、削除作業が完了します。「削除」をコミットする感じです。

`git rm -r`の「-r」はrecursive(再帰的)の略で、指定したディレクトリの中にあるファイルやディレクトリに対して削除の処理をくりかえし実行するという意味を持ちます。なので、一つのファイルを削除するだけなら問題ありませんが、ディレクトリの中身を複数削除したい場合は「-r」オプションをつけないと削除できません。

### あるファイルを削除せずにGitの管理から外すコマンド(git rm --cached)
**ステージングエリアからの削除**
`git rm --cached <ファイルパス>` コマンドを実行すると、指定したファイルがステージングエリアから削除されます。これは、次回のコミット時にそのファイルがGitリポジトリから削除されることを意味します。

**ワーキングディレクトリにファイルを残す**
--cached オプションを使用すると、そのファイル自体はワーキングディレクトリに残ります。つまり、物理的なファイルは削除されません。

**Gitの管理から外れる**
この操作により、そのファイルはGitの管理対象から外れます。つまり、今後そのファイルの変更はGitによって追跡されなくなります。

つまり、`git rm --cached`コマンドは、ワーキングディレクトリにファイルを残しつつ、そのファイルをGitの管理から外すコマンドです。

**実際の使い道**
- 環境依存の設定ファイルの管理
開発環境ごとに異なる設定ファイル（例：データベースの接続設定など）をGitリポジトリに含めたくない場合に便利です。
- 一時的なファイルの除外：
ビルドや生成されたファイルなど、バージョン管理の対象とする必要がないファイルを除外する場合に使います。

# まとめ
git checkout：直前のコミットまで戻す
git reset <file>：ステージングエリアからワーキングディレクトリにファイルを戻す
git revert：特定のコミットによる変更を打ち消す新しいコミットを作成する
git rm：ファイルを削除し、その削除した状態をコミットする

慣れればなんのことはないと思いますが、操作がわからなくなったら、またこの記事を見返したいと思います。