Gitの基本コマンドおさらい編 その2

# この記事の目的
Git初心者の皆さん、Gitって難しいですよね！
Gitのコマンド一覧に目を通して一応使い方を分かったつもりでも、いざ実践しようと思うと「あれ、僕って私ってGitのこと全然分かってなくない！？」ってなることはよくあると思います！
そんな人のために、この記事ではGitの基本的なコマンドについて、おさらいも含めて説明していきます。

⇒[本題へスキップ](#ブランチの作成と切替)

※この記事は、[Gitの基本コマンドおさらい編 その1](https://qiita.com/freshmanfreshman/items/f269ba94554fb8642d64)の続編となっています。また、この記事ではローカルリポジトリ内のみの操作を扱います。リモートリポジトリも扱った操作についてはおさらい編(その3)で解説します（執筆中）
※この記事はGitを使った経験がある人を対象として書いているため、基本的なGit用語は説明なしで使ったり、説明の順番が前後したりすることがあります。特に、ブランチの定義や役割については理解している前提とし、ここでは省かせていただきます。

# この記事で扱うコマンド
* [git branch](#git-branch)
* [git switch](#git-switch)
* [git checkout](#git-checkout-1)

# 免責事項
当サイトのコンテンツや情報において、可能な限り正確な情報を掲載するよう努めておりますが、 誤情報が入り込んだり、情報が古くなったりすることもあり、必ずしもその内容の正確性および完全性を保証するものではございません。当該情報に基づいて被ったいかなる損害について、一切責任を負うものではございませんのであらかじめご了承ください。

# ブランチの作成と切替
ここでは、ブランチを新たに作るコマンドと、ブランチを切り替えるコマンドを紹介します。
### git branch
* ```git branch BRANCHNAME```：新しいブランチ(BRANCHNAME)を作成する。
* ```git branch```：ローカルに存在する全てのブランチを表示する。現在いるブランチは※の後に表示される。

### git switch
* ```git switch BRANCHNAME```：既存のブランチ(BRANCHNAME)に移動する。
* ```git switch -c BRANCHNAME```：新しいブランチ(BRANCHNAME)に移動する。

ここで、.gitフォルダ内の構成のおさらいと共に、ブランチを切り替えた際のリポジトリの動きを追ってみたいと思います。
※ブランチ切り替え時の動きの端的な理解を目標とするため、ブランチとバージョンの関係性がだいぶ不正確になりますが、ご了承ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/2a965ea6-9579-8380-9daf-3c0325ee28da.png)

[前回の記事](https://qiita.com/freshmanfreshman/items/f269ba94554fb8642d64)で紹介したように、Gitで扱っている空間は、**リポジトリ**、**ステージ**、**ワークツリー**の3つの空間から成り立っています。ステージとワークツリーは1つずつしか存在しませんが、リポジトリ内には複数のフォルダ構造を保存することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/cc818f97-5677-90c2-eae4-dd19aca6049e.png)
上記の図は、リポジトリ内に存在するブランチとフォルダ構造を概念的に表した図です。
ブランチごとにバージョンが更新されていて、各ブランチ内で最新のバージョンが定義づけられています。
では次に、リポジトリ、ステージ、ワークツリー各々が、ブランチ切り替え時にどのような動きをするのか見てみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/26e0db59-3f1d-1d2b-799e-450cf08f0eb2.png)
まず、作業ブランチをブランチAに設定します。ワークツリーに変更を加た後 git add, git commitを行い、ステージ、リポジトリに同期させます。この状態から作業ブランチをAからCに切り替えると、フォルダ構造は次のように切り替わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/ebd1bd32-a3d4-1062-fcb0-85bbe8deed67.png)
図のように、git switchを実行して作業ブランチを切り替えると、リポジトリの内容がステージ、ワークツリーに反映されます。これが、git swithcコマンドの実行内容です。
ちなみに、ワークツリーの変更はリポジトリに反映させてからブランチを切り替えるのが基本であり、ワークツリー、ステージ、リポジトリのフォルダ構造が一致していない状態でブランチを切り替えようとするとエラーが出ます。

```
C:>git status
On branch branchC
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   index.html

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

C:>git switch branchA
error: Your local changes to the following files would be overwritten by checkout:
        index.html
Please commit your changes or stash them before you switch branches.
Aborting
```
ここではbranchCにてワークツリーに加えた変更をステージに反映させない状態で、作業ブランチをbranchAに切り替えようとしたところ、変更をコミットしてからブランチを切り替えるよう指示されています。模式的に表すと次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/655a840f-a2dc-0ecb-b540-f1b0f70bd648.png)
ちなみに変更をステージにだけ反映させてリポジトリに反映させていない場合も同じエラーが出ます。

```
C:>git status
On branch branchC
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   index.html


C:>git switch branchA
error: Your local changes to the following files would be overwritten by checkout:
        index.html
Please commit your changes or stash them before you switch branches.
Aborting
```

しかし例外として、ステージ、コミットを行わずにブランチを切り替えてもエラーが出ない場合があります。それは、切替元ブランチと切替先ブランチのリポジトリのフォルダ構造が同じ場合(※)です。
※便宜上「フォルダ構造が同じ場合」という言葉を使っていますが、より正確に表現すると「両ブランチの最新バージョンの親コミットが同じ、もしくは両ブランチの最新バージョンが親子関係にある場合」となります。ですがフォルダ構造が同じ場合は基本的にこれに該当します。
※ちなみにこの場合、ワークツリーとステージの中身はブランチ切り替え前の内容が保持されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941523/add5fc0b-0f96-6050-36be-a35f84ec9b3b.png)

```
C:>git status
On branch branchC
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   index.html

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

C:>git switch branchA
Switched to branch 'branchA'
M       index.html
```

このように、git switchコマンドを実行したときにエラーが出るケースと出ないケースを理解した上で、基本的には変更をリポジトリに反映させてからブランチを切り替えるようにしましょう。

# git checkout
gitを触ったことのある人なら誰しも一度は躓いたであろう恐怖のコマンド、それがgit checkoutです。
git checkoutで躓く原因は非常に単純明快ですので、この章を読んでくだされば二度とgit checkoutコマンドに悩まされなくてすむでしょう。
### git checkout
* ```git checkout BRANCHNAME```：既存のブランチ(BRANCHNAME)に移動する。(=```git switch BRANCHNAME```)
* ```git checkout -b BRANCHNAME```：新しいブランチ(BRANCHNAME)に移動する。(=```git switch -c BRANCHNAME```)
* ```git checkout FILENAME```：ステージの指定したファイル(FILENAME)をワークツリーに保存する。(=```git restore FILENAME```)

ひと言でいうと、**git checkoutコマンドは、git switchとgit restoreの2つのコマンドの機能を兼ね備えたコマンドである**、ということになります。上記の通り、後ろにBRANCHNAMEをつけるかFILENAMEをつけるかによって、switchとrestoreのどっちの機能を実行するかが決まります。
ちなみにgit switchとgit restoreは、Git Ver2.23で初めてリリースされました。
git checkoutはこの2つのコマンドの機能以外にも複数の機能を持っていて利用者の混乱を招いていたという背景から、git switchとgit restoreがリリースされたのです。今後git checkoutを使うメリットはなくなっていくでしょうから、積極的にgit switch, git resetを使うようにしましょう。


いかがでしたか！？
当記事は単なるコマンドの説明にとどまらず、包括的な理解につながるよう意識して執筆しました。
分かりづらい点や間違っている点があったら是非ご指摘いただけると幸いです！
よかったら高評価とチャンネル登録よろしくお願いします！