【初心者にやさしい】イメージで理解する『git コマンド』

# 本記事の目的
　本記事の目的は、 __「イメージのわきずらいgit」に対して、頭の中でイメージしながら使いこなしていけるようになる方を一人でも多く増やすこと__ です。
　そのために一つ一つのgit コマンドを図と共に理解できるように説明していきます。

# gitの3要素
　gitは、「__誰が__」「__いつ__」「__何を__」「__何のために__」変更したのかということを時系列で簡単に把握することができる便利なツールです。
 そんなgitには使いこなすために知っておくべき3つの要素があると私は考えています。

* ワークツリー
* ステージ
* ローカルリポジトリ

　以下の図を見ていただくと分かりやすいと思いますが、 __gitでは主にこの3つの領域を駆使して変更履歴を管理していきます。__ これからご説明するコマンドも、この3つの領域を考慮しながら説明させていただくのでしっかりと理解しておきましょう。ただしざっくりとした理解で大丈夫だと思います。
![gitの3要素.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/8865ac7b-5a53-c2a1-a087-5fc8bfef7d2a.jpeg)

# git コマンド(変更を反映させるためのコマンド集)
　まずは基本的に用いる「__変更した分を反映させるためのコマンド__」です。
## git add(変更分をワークツリーからステージへ）
　git addは、「__ワークツリーで変更を加えた分をステージに上げるためのコマンド__」です。使用するコマンドと動きのイメージは以下の図の通りです。
![git addイメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/a6d47aac-dab0-5d2d-a944-5fa3c63c80e7.jpeg)
## git commit（変更分をステージからローカルリポジトリへ）
　gitでは、 ローカルリポジトリに変更分を保存することを「__コミットする__」と言います。
　git commitは、「__ステージに上げた分をローカルリポジトリに保存するためのコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git commit イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/f50b55c6-b4de-1f8f-6a58-6d67bb0058a9.jpeg)
```
# git commitのみの場合エディタが起動し、そこでコミットメッセージを入力することになる
$ git commit

# git commit -m 'メッセージ'の場合、コマンド上でメッセージを入れた上でコミットできる
$ git commit -m 'test.htmlファイル作成'
```
## git status（各領域間での変更状況を確認）
　git statusコマンドは、「__ワークツリーとステージ間、もしくはステージとローカルリポジトリ間の変更状況を表示する__」コマンドです。使用するコマンドと動きのイメージは以下の図の通りです。
![git status イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/d93d07ea-41ff-c0a0-4abd-6f8008475487.jpeg)
## git diff（各領域間での変更差分を確認）
　git diffコマンドは、git statusコマンドと少し似ていますが、こちらは「__差分を詳しく表示するコマンド__」です。「__git diff__」と「__git diff --staged__」の２種類があります。使用するコマンドと動きのイメージは以下の通りです。
![git diff git diff --staged イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/d48820fd-64d8-9100-8128-f279a1bbfeb9.jpeg)
## git rm（ファイルやディレクトリを削除する）
　git rmコマンドは「__ファイルやディレクトリを削除したという記録を反映させるためのコマンド__」です。主に以下の2パターンを覚えておきましょう。
```
# ワークツリーとローカルリポジトリから削除する
git rm ファイル名
git rm -r ディレクトリ名

# ワークツリーには残すがローカルリポジトリからは削除する = 実際のファイルは残すが、変更履歴には載せない
git rm --cached ファイル名
```
　使用するコマンドと動きのイメージは以下の通りです。
### git rmコマンドの場合
![git rm イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/d2ddfcf1-bb4a-6b67-16a3-8b229a2a31a3.jpeg)
### git rm --cachedコマンドの場合
![git rm --cached イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/1aaa8da6-a623-1426-aa77-4933baff36fc.jpeg)

::: note info
__git rm --cached__ は、機密情報が入ったファイルなど、ワークツリーには実ファイルを残しておきたいけど安全のためにgitには追跡させたくないからやっぱり消すといった状況で使われることが多い。
:::

## git mv（ファイル名を変更する）
　git mvコマンドは「__ファイル名を変更するときに用いるコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git mv イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/529f37d2-4f43-18d9-241b-edc6118fedc8.jpeg)
```
# git mv home.html home2.htmlは以下と同じこと
$ mv home.html home2.html  -- ①ワークツリーでファイル名が変わる
$ git rm home.html         -- ②ローカルリポジトリから「home.html」が削除される
$ git add home2.html       -- ③リネーム後ファイルがステージへ上げられる
```
# git コマンド(変更を取りやめる/やり直すコマンド集)
次に「__変更した分を取りやめたりやり直したりするコマンド__」を説明いたします。
## git reset HEAD コマンド（ステージに上がっている変更分を取り消す）
　git reset HEADコマンドは、「__ステージに上げてしまった変更分を取り消すコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git reset HEAD イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/84f4e6c6-3718-c336-85de-27d71b96df72.jpeg)
## git checkout --<ファイル名>　コマンド（ワークツリーでの変更分を取り消す）
　git checkout --<ファイル名>コマンドは、「__ワークツリーでの変更を取り消すコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git checkout -- イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/a9d16004-b83c-080d-c35f-84b9caab0976.jpeg)

:::note info
__git checkout -- <ファイル名>__ の他に、 git restore <ファイル名>__ というやり方もある。
:::
## git commit --amend コマンド（直前のコミットを取り消してやり直す）
　git commit --amend コマンドは、「__直前のコミットをやり直すためのコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git commit --amend イメージ①.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/d1abf780-8cd7-0a50-5003-e2efac8c7409.jpeg)
↓
![git commit --amend イメージ②.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/10e726e0-0f6f-5844-2a7e-447777b54eb6.jpeg)
# git コマンド(リモートリポジトリとのやり取り）
　これまではあくまで「ローカル環境」でのgit コマンドについてご説明しました。しかし、gitには「リモートリポジトリ」と
のやり取りをして、他の人が変更したものを自分のところにも取り入れるなどの「__共有__」操作を行うことができるという大きな特徴を持っています。

　そこで、ここからは「__リモートリポジトリとのやり取り__」に使用するコマンド集をご説明していきます。
## git push 
　git pushコマンドは「__ローカルリポジトリに保存したコミットをリモートリポジトリに共有するためのコマンド__」です。使用するコマンドと動きのイメージは以下の通りです。
![git push イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/542c22c3-cfbc-4ef4-eed4-0fe7745f1ad4.jpeg)
```
# 基本的にgit push <リモートリポジトリ名> <リモートブランチ名>とする
$ git push origin main
```
　尚、リモートリポジトリ名やリモートブランチ名を指定せずとも省略記法で出来てしまう方法もありますが、ここでの説明は割愛させていただきます。
## git fetch ~ git merge
　git fetchとは「__リモートリポジトリ上の特定のブランチでの変更分をローカルのリモート追跡ブランチに取り込むためのコマンド__」です。そして、git mergeは「__ローカルのリモート追跡ブランチに取り込んだ内容を実際にローカルリポジトリのブランチに結合させるコマンド__」です。
　「リモート追跡ブランチ」という意味不明な言葉も出ていますし、これだけでは理解できないと思いますので、以下の図などをご覧ください。
![git fetch イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/c99278da-4106-9fed-5331-2a146bd99237.jpeg)
```
# ①リモートの「main」ブランチで「index.htmlファイル」に「<p>20230109 git fetchの練習</p>」というpタグを追加しとします。

# ②リモートのmainブランチでの変更分を「fetch」
$ git fetch origin main
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 743 bytes | 185.00 KiB/s, done.
From https://github.com/hiddy0329/git-tutorial
 * branch            main       -> FETCH_HEAD
   31525b5..153da33  main       -> origin/main  

# 上のところで、「31525b5..153da33  main       -> origin/main  」となっている部分に注目。
# リモートのmainブランチからリモート追跡ブランチである「origin/main」ブランチへ変更分が取り込まれている。

# ③現在のローカル上のブランチを確認する
$ git branch -a
  feature
  hotfix
* main
  remotes/backup/main
  remotes/origin/feature
  remotes/origin/main

# ④「remotes/origin/main」というのがリモート上のmainブランチの内容を追跡するリモート追跡ブランチなので、このブランチの中身を見てみる。
$ git checkout remotes/origin/main
Note: switching to 'remotes/origin/main'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 153da33 20230109 git fetchの練習を追記

#　⑤index.htmlファイルの中身を見ると、追記した分が取り込まれていることが分かる
$ ls
hoge.html	home3.html	main.html	tmp.html
home.html	index.html	test.html	tmp.txt

$ cat index.html
<h1>hello world</h1>
<p>my name is Ken</p>
<p>git diffコマンドで差分を表示</p>
<p>git diff --stagedとするとステージとローカルリポとの差分を表示</p>
<p>git commit --amend</p>
<p>git rmコマンドの練習</p>
hellohello
<p>20230109 git fetchの練習</p>

# ⑥mainブランチへ戻る
$ git checkout main
Previous HEAD position was 153da33 20230109 git fetchの練習を追記
Switched to branch 'main'
Your branch and 'origin/main' have diverged,
and have 11 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

# ⑦origin/mainブランチにリモート上の変更が取り込まれていることを確認したので、今度はローカルのmainブランチに取り込みを実行
$ git merge origin/main
Merge made by the 'ort' strategy.
 index.html | 1 +
 1 file changed, 1 insertion(+)

$ ls
feature.html	home.html	index.html	test.html	tmp.txt
hoge.html	home3.html	main.html	tmp.html

# ⑧ローカルのmainブランチに変更分が取り込まれたことを確認
$ cat index.html
<h1>hello world</h1>
<p>my name is Ken</p>
<p>git diffコマンドで差分を表示</p>
<p>git diff --stagedとするとステージとローカルリポとの差分を表示</p>
<p>git commit --amend</p>
<p>git rmコマンドの練習</p>
hellohello
<p>20230109 git fetchの練習</p>

```
　分かりにくくて恐縮ですが、git fetchでは一旦「リモート追跡ブランチ」というところに仮で変更分を取り込むわけですね。その後、実際にローカルのブランチに取り込んで大丈夫であれば取り込むといった流れでしょうか。
## git pull
　git pullは先ほどの「__git fetch ~ git mergeを一度に行なってしまうコマンド__」です。イメージは以下の通りです。
![git pull イメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/2126de65-9aa1-fef3-484a-d777ba230da7.jpeg)
　git pullでは、一度に「merge」までしてしまうため、「__コンフリクト__」に気をつける必要があります。この記事では「git fetch」や「git pull」をイメージで理解することのみに留めさせていただきますが、詳しく挙動を知りたいというような方には以下の記事などがとても参考になります。

* [git pull(プル)とは何か？使い方を実例で解説｜引数が無い場合の処理内容やFETCH_HEADとは何か？–rebaseオプションの使い方](https://prograshi.com/general/git/how-to-use-git-pull/)
* [【初心者向け】git fetch、git merge、git pullの違いについて](https://qiita.com/wann/items/688bc17460a457104d7d)

# 次回の記事
　今回は、基本的なgitコマンドでの操作についてイメージを持って理解していただくことを目的にご説明しました。次回の記事では、「ブランチ」などの概念に踏み込んでご説明できたらと思います。