【もう慌てない】Git操作まとめ

# はじめに
* この記事は筆者の学習と理解の整理のために書かれたものです。
* 「なんとなくgitは知ってるけどその操作に不安がある」という方を対象読者としています。
* 間違い等あれば、お気軽にコメントにてご指摘ください。
* 本記事が誰かのGit学習の助けになれば幸いです。
# Gitとは

分散型バージョン管理システムの1つ。
* 分散型……各々のPCにローカルリポジトリをもつような仕組みのこと、対となる言葉に「集中型」がある
* バージョン管理……プログラムの状態をバージョンとして管理し、いつでも以前の状態に戻せるようにすること。例えばリリースした機能にバグが見つかった場合にその機能を追加する前の状態に戻すなどということが簡単にできる。
# 用語説明
ここでは簡単な説明しか行わないので、より詳細な説明が気になる方は適宜調べてください。
| 用語 | 説明 |
|:-:|:-:|
| 作業ツリー | 開発をしているディレクトリツリーのこと、普段ファイルを編集したり作成したりという処理はここで行っている。ワークツリーとも言われる。 |
| コミット |   ファイルの変更等をリポジトリに記録すること。|
| ステージングエリア | 作業ツリーの内容をコミットする際に経由するエリア。インデックスとも言われる。 |
| ステージする |  `git add`を使って、作業ツリーからステージングエリアへとファイルをコピーすること。 |
| ブランチ | 一連のコミット履歴のこと。またその履歴の先端のコミットを指すポインタのこともブランチという。|
| HEAD | 最新のコミットを指すポインタ、平たくいうと現在見ているコミットのこと。 |
| リモート追跡ブランチ | リモートブランチの状態をローカルに記憶する特殊なブランチ、後述するpullやpushなどの操作を行うと、リモートの状態に合わせて移動する。 |


## git init
```
git init
```
* 空のリポジトリを作成するとき、すなわちgitを用いてバージョン管理を始めるときに使用する。
* 開発プロジェクトのトップとなるディレクトリで実行する。
* `.git`ディレクトリが作成され、バージョン管理に必要な情報が格納されていく。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ☆☆☆☆☆ |

## git add
```
git add <ファイルパス>
git add <ディレクトリパス>
```
* 作業ツリーの内容をステージングエリアにコピーする。
* 主に現在の作業ツリーの内容をコミットしたいときに使用する。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ☆☆☆☆☆ |
### オプション
| オプション | 説明 |
|:-:|:-:|
| -u  | ワークツリー全体で追跡されたすべてのファイルが更新される  |
<details open><summary>使用例</summary>

```bash
# dir配下のfile1をステージングエリアへコピーするとき
$ git add dir/file1
# カレントディレクトリ配下の全てのファイルをステージングエリアへコピーするとき
$ git add .
# dir配下の全てのファイルをコピーするとき
$ git add dir
# README.txtをステージングエリアへコピーするとき
$ git add README.txt
```

</details>

## git branch
```
git branch
```
* 現在ローカルに存在しているブランチが一覧表示される。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ☆☆☆☆☆ |
### オプション
| オプション | 説明 |
|:-:|:-:|
| -d | 指定したブランチを削除したいときに用いる。このブランチにおける変更がどのブランチにもmergeされていない場合は警告が出て失敗する。 |
| -D| 指定したブランチを削除したいときに用いる。`-d`とのときとは違い強制的に削除する。  |
| -r|リモート追跡ブランチの一覧を表示する。|
| -u| 指定したリモートブランチをチェックアウトしているローカルブランチの上流ブランチとして設定する。|
| -vv | ローカルブランチに上流ブランチが設定されてるかどうかを確認する。|
|-a|リモートブランチを含んだブランチの一覧を表示する。|
|--no-merged | HEADにマージされていないブランチの一覧を表示する。|
|merged|すでにHEADにマージ済みのブランチの一覧を表示する。|
|-m|ブランチの名前を変更する、|

<details open><summary>使用例</summary>

```shell
$ git branch
* develop # 現在いるブランチ
  unnecessary
  master

$ git branch -D unnecessary # unnecessaryブランチが削除される
$ git branch
* develop
  master

$ git branch -r # リモート追跡ブランチの一覧を表示する。
  origin/edit
  origin/master

$ git checkout master
$ git branch -v
  edit   6848744 edit in editBranch
* master f6bc145 first commit #　上流ブランチ未設定
#masterブランチの上流ブランチを、リモートブランチを表すリモート追跡ブランチで指定し設定する。
$ git branch -u origin/master
  edit   6848744 edit in editBranch
* master f6bc145 [origin/master] first commit #上流ブランチが設定できた。これでpullするときの引数を省略できる。

$ git branch -a # リモートブランチを含んだブランチの一覧を表示する。
  edit
* master
  remotes/origin/edit
  remotes/origin/master

$ git merge edit
$ git branch --merged # すでにHEADにマージ済みのブランチの一覧を表示する。
  edit
* master 
 
$ git branch -m main #masterブランチの名前をmainに変更
$ git branch
  edit
* main
```

</details>


## git checkout
```
git checkout <ブランチ名>
git checkout <コミット>
```
* 指定したブランチ、コミットをチェックアウトする。
* 引数にブランチを指定するとそのブランチをチェックアウトする。
* ブランチ以外を指定すると切り離されたHEAD状態になる。
* コミットの指定はコミットIDで行う。コミットIDの確認には`git log`を用いる。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ☆☆☆☆☆ |
### オプション

| オプション | 説明 |
|:-:|:-:|
| -b | 指定した名前で新しいブランチを作成し、かつそのブランチに移動する。 |

<details open><summary>使用例</summary>

```shell
$ git checkout edit
$ git branch
* edit
  master 

$ git checkout -b test
$ git branch
  edit
  master 
* test    # testブランチが作成されかつそのブランチに移動している。

```
</details>

## git commit

```
git commit
```
* ステージングエリアに乗せた内容をコミットする際に使用する。
* これを実行すると、コミットメッセージを入力するためにエディタが立ち上がるので、そのときは適宜入力して保存しエディタを終了する。
* もしコミットメッセージを入力するタイミングでやっぱりコミットを中止したくなった場合は、コミットメッセージを全て消し、保存してエディタを終了すれば良い。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ★★☆☆☆ |
### オプション
| オプション | 説明 |
|:-:|:-:|
| -m | 引数に入力した文章をコミットメッセージとして使用する。  |
<details open><summary>使用例</summary>

```shell
$ git add README.txt            #変更をステージして 
$ git commit -m "first commit"  # コミットする。コミットメッセージとして "first commit"を指定している。
```
</details>

## git status
```
git status
```
* 現在の作業ツリーやステージングエリアがどのような状況なのかを確認するときに使用する。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ☆☆☆☆☆ |

<details open><summary>使用例</summary>

```shell
$ git add README.txt
$ git status
On branch edit
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   README.txt # ステージしているがコミットされてない内容が表示されている。
```
</details>

## git help
```
git help
```
* 主要コマンドとその説明の一覧が表示される。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★☆☆ |
|  危険度    | ☆☆☆☆☆ |

### オプション
| オプション | 説明 |
|:-:|:-:|
| \<command>  | 指定したコマンドに関するヘルプページが表示される |

<details open><summary>使用例</summary>

```shell
$ git help commit #commitに関するヘルプページが表示される。
```
</details>

## git log
```
git log
```
* これまでに行ったコミットの履歴を見ることができる。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ☆☆☆☆☆ |

### オプション
| オプション | 説明 |
|:-:|:-:|
| --oneline | 各コミットを1行で表示する。 |
|  -- <ファイル名> | 指定したファイルの履歴を表示する。  |
| --name-status|変更したファイルを表示する。|
| --graph| コミット履歴がグラフの形で表示される。|
<details open><summary>使用例</summary>

```shell
$ git log --oneline --all --graph # 個人的にこの指定が見やすい
* f527558 (HEAD -> master) edit in master
| * 96b828d (edit) add README.txt
|/
* 6848744 (origin/edit) edit in edit
* f6bc145 (origin/master) first commit
```
</details>

## git show
```
git show
git show <コミット>
```
* コミットの詳細を確認するときに用いる。
* コミットの情報と`git diff`した結果を表示してくれる。
* コミットを指定するとそのコミットの詳細を表示でき、指定しない場合は直近のコミットが暗黙の内に指定される。
* コミットの指定はコミットIDで行う。コミットIDの確認には`git log`を用いる。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★☆☆☆ |
|  危険度    | ☆☆☆☆☆ |

<details open><summary>使用例</summary>

```shell
$ git show
Author: #省略
Date:   Tue Nov 22 16:56:34 2022 +0900

    edit in master

diff --git a/text1.txt b/text1.txt
index c8164ca..666f016 100644
--- a/text1.txt
+++ b/text1.txt
@@ -1,2 +1,2 @@
-first
-second in edit
\ No newline at end of file
+first in master
+second in edit

$ git show 684874 #指定したいコミットのハッシュ値を入力
commit 6848744edc17e9ec6c1ae8a9e772ba55dd55490d (origin/edit)
Author: # 省略
Date:   Tue Nov 22 15:05:20 2022 +0900

    edit in edit

diff --git a/text1.txt b/text1.txt
index fe4f02a..c8164ca 100644
--- a/text1.txt
+++ b/text1.txt
@@ -1 +1,2 @@
-first
\ No newline at end of file
+first
+second in edit
\ No newline at end of file
```
</details>

## git diff
```
git diff
git diff HEAD
git diff <コミット1> <コミット2>
```
* 引数を何も指定しない場合は、作業ツリーとステージングエリアの差を表示する。
* HEADを指定した場合は、作業ツリーとHEADの差を表示する。
* 2つコミットを指定した場合はそのコミット間の差を表示する。
* コミットの指定はコミットIDで行う。コミットIDの確認には`git log`を用いる。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★☆☆ |
|  危険度    | ☆☆☆☆☆ |

### オプション
| オプション | 説明 |
|:-:|:-:|
| -- <ファイル名>|コミット間の差を指定したファイルに絞って表示する。|
|--staged | ステージングエリアとHEADの間の差を表示する。 |
<details open><summary>使用例</summary>

```shell
$ git diff
diff --git a/text1.txt b/text1.txt
index 666f016..28a8ab0 100644
--- a/text1.txt
+++ b/text1.txt
@@ -1,2 +1,2 @@
-first in master
+first in master two times
 second in edit

$ git diff --staged
（ステージングエリアとHEADが同じ状態なので何も表示されない。）
$ git diff -- README.txt
（README.txtに変更を行っていないためなにも表示されない）
$ git diff HEAD^ HEAD #HEADのひとつ前のコミットとHEADを比較する、もちろんコミットの指定はハッシュ値を用いてもよい。
diff --git a/text1.txt b/text1.txt
index c8164ca..666f016 100644
--- a/text1.txt
+++ b/text1.txt
@@ -1,2 +1,2 @@
-first
-second in edit
\ No newline at end of file
+first in master
+second in edit
```

</details>


## git merge
```
git merge <mergeしたいブランチ>
```
* 他ブランチで作業した内容を、今チェックアウトしているブランチに取り込みたいときに使用する。
* mergeは（オプションを特に指定しなければ）新しいコミットを作るので、コミットメッセージを入力するためにエディタが立ち上がることがある。その場合は`git commit`のときと同様の対処をすれば良い。
<details><summary>コンフリクトが発生した場合</summary>

対処方法は以下の通り。
1. コンフリクトが発生した箇所を適切に編集する。
1. `git add`コマンドでその変更をステージする。
1. `git commit`コマンドでコミットを行う。コミットメッセージの入力が求められたら適切に入力しコミットを完了する。
1. コンフリクトは解消される！

もしコンフリクトの解消をせずにmergeを取りやめたい場合は以下のコマンドを実行する。
```shell
git merge --abort
```
すると`git merge`実行前の状態に戻る。

</details>

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ★★★☆☆ |

### オプション
| オプション | 説明 |
|:-:|:-:|
| -m  | 引数に入力した文章をコミットメッセージとして使用する。 |
| --ff  |  早送りマージができるならそれを実行する。つまりマージコミットが作られない。 |
|--no-ff|早送りマージができる場合でもマージコミットを作成する。|
|--ff-only|可能な場合は早送りマージを行い、そうでない場合はマージを拒否する。|
<details open><summary>使用例</summary>

```shell
 $ git merge edit
Merge made by the 'ort' strategy.
 README.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 README.txt

$ git merge edit --no-ff -m "merge commitを作成"
Auto-merging text1.txt
CONFLICT (content): Merge conflict in text1.txt
Automatic merge failed; fix conflicts and then commit the result.
# コンフリクトを解消する
$ git add text1.txt
$ git commit
[master 2a1418f] merge commitを作成
```
</details>

## git cherry-pick
```
git cherry-pick <コミット>
git cherry-pick <コミット(最初)>..<コミット(最後)>
git cherry-pick <コミット1> <コミット2> <コミット3>
```
* 任意にコミットを指定し、そのコミットにおける変更をHEADに適用させるためのコマンド。
* 連続したコミットを「ここからここまで」というふうに指定しcherry-pickしたい場合は2番目のような書き方をする。
* 一度に複数のコミットを指定したい場合は3番目のような書き方をする。指定した順に適用される。
* コミットの指定はコミットIDで行う。コミットIDの確認には`git log`を用いる。
* cherry-pickにより作られるコミットIDは、コピー元のコミットIDとは異なるIDになるので注意する。

<details><summary>コンフリクトが発生した場合</summary>

対処方法は以下の通り。
1. コンフリクトが発生した箇所を適切に編集する。
1. `git add`コマンドでその変更をステージする。
1. `git cherry-pick --continue`を実行し、エディタが立ち上がれば適切にコミットメッセージを変更しエディタを終了する。
1. コンフリクトは解消される！

もしコンフリクトの解消をせずに`cherry-pick`を取りやめたい場合は以下のコマンドを実行する。
```shell
git cherry-pick --abort
```
すると`git cherry-pick`実行前の状態に戻る。
</details>

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ★★★☆☆ |

### オプション
| オプション | 説明 |
|:-:|:-:|
| -e  | コミットメッセージを編集したいときに用いる。<br>（デフォルトではcherry-pickしたときのコミットメッセージは元々のコミットメッセージと同じものになる。）  |
| -n  | コミット直前の、ステージした状態までで処理を止めたいときに用いる。  |
| --abort  | cherry-pickを取りやめたいときに用いる。  |

<details open><summary>使用例</summary>

次のようなコミット列があり、それぞれの内容は`cherry-pick-test.txt`に1行ずつ「commit ○ in <ブランチ名>」を追加するというものであったとする。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649218/e5f6c10f-d7d5-5342-f87a-f0b9bb9996b0.jpeg" width="300px">

cherry-pick-testブランチの最新の内容は以下。
```plaintext:cherry-pick-test.txt
commit A
commit D in cherry-pick-test
commit E in cherry-pick-test
commit F in cherry-pick-test
```
masterブランチの最新の内容は以下。
```plaintext:cherry-pick-test.txt
commit A
commit B in master
commit C in master
```

ここでcherry-pickを用いてmasterブランチのコミットCの次にコミットEの変更をつぎたしてみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649218/d71eade4-374a-4209-54ad-b238c3003aac.jpeg" width="300px">
```shell
$ git checkout master
Switched to branch 'master'
$ git log --oneline --all --graph
* fd02c3e (HEAD -> master) commit C
* 31f354a commit B
| * bd99fbe (cherry-pick-test) commit F
| * 1b1f6f6 commit E
| * 38ea831 commit D
|/
* b2b9b58 commit A
$ git cherry-pick 1b1f6f6 # commit Eを指定
Auto-merging cherry-pick-test.txt
CONFLICT (content): Merge conflict in cherry-pick-test.txt
error: could not apply 1b1f6f6... commit E
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
#コンフリクトが発生する。
```
![スクリーンショット 2022-11-30 175547.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649218/9233810e-28f8-0d2c-0c3e-cc467bd108cd.png)
今回はコミットEの内容だけ継ぎ足したかったので次のように編集する。
![スクリーンショット 2022-11-30 180040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649218/4ab66678-b1aa-83bd-4473-7a55b34fd486.png)
```
# コンフリクトの編集が終わったので、それをステージし改めてcherry-pickを行う
$ git add .
$ git cherry-pick --continue
[master 66926c3] commit E
 Date: Wed Nov 30 17:42:56 2022 +0900
 1 file changed, 2 insertions(+), 1 deletion(-)
# 完了！
```
</details>

## git config
```
git config <設定項目名>
git config <設定項目名> <変更先の値>
```
* gitの設定を確認したり編集したいときに用いる。
* 確認したいときは1番目の書式を用いる。
* 編集したいときは2番目の書式を用いる。
* なお設定ファイルは3種類存在し、オプションでどのファイルの設定を変更するかを指定することができる。

|  | 対象範囲 | 設定ファイルの場所 | オプション |
|:-:|:-:|:-:|:-:|
| system  | マシン全体  | /etc/gitconfig  | --system |
| global  |  使用しているユーザー |  ~/.gitconfig | --global|
| local  |  今いるリポジトリ |  .git/config | --local|

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ★☆☆☆☆ |

### オプション
| オプション |説明 |
|:-:|:-:|
| -l  |  設定項目の一覧表示をしたいときに用いる。 |
| -e  | 設定ファイルをエディタを開いて編集したいときに用いる。  |
<details open><summary>使用例</summary>

```shell
# 設定しているメールアドレスの確認
$ git config user.email
example@example.com
# systemの設定ファイルをエディタで開く
$ git config --system -e
# globalにて設定している設定項目を一覧表示する
$ git config --global -l
# コミットメッセージを編集するときに立ち上がるエディタとしてVScodeを指定する
$ git config --global core.editor 'code --wait'
```

</details>

## git mv
```
git mv <元の名前> <新しい名前>
git mv <ファイル> <移動先ディレクトリ>
```
* ファイルの名前を変更したり、ファイルを移動したりするときに用いる。


|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ★☆☆☆☆ |
<details open><summary>使用例</summary>

ディレクトリ構成は以下のようなものとする。
```
example_dir
│  old.txt
│
├─test1
└─test2
    └─inside
```

```shell
# old.txtの名前をnew.txtに変更
$ git mv old.txt new.txt
# new.txtをtest1ディレクトリに移動
$ git mv new.txt test1
# new.txtをtest1ディレクトリからtest2ディレクトリ内部のinsideディレクトリに移動
$ git mv test1/new.txt test2/inside
```
</details>

## git rebase
```
git rebase <ブランチ>
```
* 今チェックアウトしているブランチの根元を指定したブランチの先端に付け替える。
* やっていることはcherry-pickの繰り返し。
* よって移動先のコミットは移動前のコミットとは別物になる。
* 注意点として`rebase`後のコミットをリモートに`push`する場合は強制pushを行う必要がある。
参考：[なぜrebase後に強制プッシュをする必要があるのか](https://qiita.com/hitochan777/items/ea08df354b42be57e5fc)


<details><summary>コンフリクトが発生した場合</summary>

対処方法は以下の通り。
1. コンフリクトが発生した箇所を適切に編集する。
1. `git add`コマンドでその変更をステージする。
1. `git rebase --continue`を実行し、エディタが立ち上がれば適切にコミットメッセージを変更しエディタを終了する。
1. コンフリクトは解消される！

もしコンフリクトの解消をせずに`rebase`を取りやめたい場合は以下のコマンドを実行する。
```shell
git rebase --abort
```
すると`git rebase`実行前の状態に戻る。

</details>

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★☆ |
|  危険度    | ★★★☆☆ |

<details open><summary>使用例</summary>

```shell
# developブランチの根元をmasterブランチの先端へ付け替える
git checkout develop
git rebase master # ここでコンフリクトが発生する場合がある。
```

</details>

## git reset
```
git reset --soft <コミット>
git reset --mixed <コミット>
git reset --hard <コミット>
```
* 使用機会は大きく分けて以下の2パターンがある。
    1. 作業ツリーやステージの内容を以前のコミットの内容に合わせたいとき。
    1. いくつかのコミットを取り消したいとき。
* つまりは、HEADを移動させるためのコマンドである。
    * HEADを過去のコミットに合わせることが上の1,2でやりたいことの本質であり、`git reset`はそれを実現してくれる。
* 引数にとるコミットには、HEADを移動させたいコミットを指定する。
* いずれの場合も作業ツリーの内容が失われたりする可能性があるので実行する際は注意すること。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★☆☆ |
|  危険度    | ★★★★★ |

### オプション
以下、引数に指定したコミットのことを単に「コミット」と書くことにする。
| オプション | 説明 |
|:-:|:-:|
| --soft  |  コミット記録→消える <br> ステージングエリア→コミット  |
| --mixed  | 「（引数として指定した）コミットを行った」という記録が消え、さらにステージングエリアも空の状態になる。作業ツリーはコミット前の状態に戻る。 |
| -- hard |コミット記録、ステージングエリア、作業ツリー、これら全てがコミット前の状態に戻る。完全にコミットを消し去りたいときに使う。|

<details open><summary>使用例</summary>
ここでは実際にコミット履歴を操作してみる。
現在のコミット履歴は以下。

```shell
$ git log --oneline
b96e2f7 (HEAD -> master) commit C
6c412a7 wrong commit
b3e7473 commit B
11e2592 commit A
```
そして上4つのそれぞれのコミットの内容は、git_reset_test.txtというファイルに1文ずつコミットメッセージと同じ文章を追加していくという内容になっている。
```plaintext:git_reset_test.txt
commit A　　　　 (<-- commit Aで追加した1文)
commit B　　　　 (<-- commit Bで追加した1文)
wrong commit    (<-- wrong commitで追加した1文)
commit C　　　　 (<-- commit Cで追加した1文)
```
さらに、未コミットの状態でこれに加えてさらに2文追加する。
```plaintext:git_reset_test.txt
commit A　　　　 (<-- commit Aで追加した1文)
commit B　　　　 (<-- commit Bで追加した1文)
wrong commit    (<-- wrong commitで追加した1文)
commit C　　　　 (<-- commit Cで追加した1文)
stage           (<-- 未コミットだがステージ済み)
worktree        (<-- 未コミットでステージングもまだ)
```
とりあえず`git status`を打ってみる。
```shell
$ git status       
On branch master
Your branch is ahead of 'origin/master' by 11 commits.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   git_reset_test.txt

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:   git_reset_test.txt
```

この状態で`git reset`コマンドがどのような結果をもたらすかを確認する。
```shell
$ git reset --soft b96e2f7 # commit Cを指定
# 何も変化無し
$ git reset --mixed b96e2f7 # commit Cを指定
Unstaged changes after reset:
M       git_reset_test.txt
# ステージングエリアの内容がcommit C直後のものになるため結果的にステージングエリアが空になる
$ git reset --hard b96e2f7 # commit Cを指定
HEAD is now at b96e2f7 commit C
# 作業ツリーまでがcommit C直後のものに上書きされるので作業ツリー、ステージングエリアともに空になる。
$ git reset --soft 6c412a7 # wrong commitを指定
# commit Cのコミット履歴だけが失われる、一方作業ツリーとステージングエリアにおける変更は失われないためステージングエリアには「commit C」という1文を追加した差分が残る。
$ git reset --mixed 6c412a7 # wrong commitを指定
Unstaged changes after reset:
M       git_reset_test.txt
# ステージングエリアまでがwrong commit直後の内容に上書きされる。そのため先ほどステージングエリアにあった差分が作業ツリーにまで落ちてくる。
$ git reset --hard 6c412a7 # wrong commitを指定
HEAD is now at b3e7473 commit B
# commit Cにおける変更が全て失われ、wrong commit直後の内容に上書きされる。作業ツリー、ステージングエリアともにクリーンな状態で「commit C」という1文は完全に失われている。
$ git reset --hard b3e7473 # commit Bを指定
HEADをcommit Bに移動させることでwrong commitでのコミット内容を消すことができた。
$ git log --oneline
b3e7473 (HEAD -> master) commit B
11e2592 commit A
# 確かにcommit BへとHEADが移動している。
```

</details>

## git reflog
```
git reflog
```
* 自分のgit操作のログ履歴を見ることができ、誤ったgit操作をしてしまった場合でも元に戻すことができる。詳しくは使用例を参照。
* `reflog`とは、reference + log のこと

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★☆☆☆ |
|  危険度    | ★★★☆☆ |
<details open><summary>使用例</summary>

以下は`git reset`の使用例の続きです。そちらも合わせてご確認ください。
```shell
$ git reflog
b3e7473 (HEAD -> master) HEAD@{0}: reset: moving to b3e7473 # <-- git reset --hardでcommit BへHEADを移動したときの履歴
6c412a7 HEAD@{1}: reset: moving to 6c412a7  # <-- git reset --mixedの履歴
6c412a7 HEAD@{2}: reset: moving to 6c412a7  # <-- git reset --softの履歴
b96e2f7 HEAD@{3}: reset: moving to b96e2f7  # <-- git reset --hardの履歴
b96e2f7 HEAD@{4}: reset: moving to b96e2f7  # <-- git reset --mixedの履歴
b96e2f7 HEAD@{5}: reset: moving to b96e2f7  # <-- git reset --softの履歴
b96e2f7 HEAD@{6}: commit: commit C
6c412a7 HEAD@{7}: commit: wrong commit
b3e7473 (HEAD -> master) HEAD@{8}: commit: commit B
11e2592 HEAD@{9}: commit: commit A
```
ここで誤ってcommit AにHEADを移動させてしまったとする。
```shell
$ git reset --hard  11e2592 # commit Aを指定
HEAD is now at 11e2592 commit A
$ git log --oneline
11e2592 (HEAD -> master) commit A
```
失われてしまったcommit Bを取り戻すために`git reflog`で操作ログを確認し`git reset`で元に戻す。
```shell
$ git reflog
11e2592 (HEAD -> master) HEAD@{0}: reset: moving to 11e2592
b3e7473 HEAD@{1}: reset: moving to b3e7473
6c412a7 HEAD@{2}: reset: moving to 6c412a7

#戻りたいのはgit resetをする前、つまり上のログの中のHEAD@{1}の状態なので、それを指定しgit resetする。
$ git reset --hard HEAD@{1}
HEAD is now at b3e7473 commit B
$ git log --oneline
b3e7473 (HEAD -> master) commit B
11e2592 commit A
# commit Bに戻って来れた！！
```
</details>



## git rm
```
git rm <ファイル>
git rm -r <ディレクトリ>
```
* gitの管理下にあるファイルやディレクトリを削除したいときに用いる。
* 削除したファイルは以降gitから無視される。
* 一方ですでに作られたコミットからは削除されない。
 
|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ★★★★★ |

### オプション
| オプション | 説明 |
|:-:|:-:|
|  -r |  引数として指定したディレクトリ配下全てのファイルを削除する。 |
|  --cached |  作業ツリーにファイルは残しつつ、ステージから取り除きたいときに使用する。 |

<details open><summary>使用例</summary>

secret.txtを作成しコミットする。
```shell
git add secret.txt
git commit -m "secret.txtを作成"
```
secret.txtを削除する。
```shell
$ git rm secret.txt
rm 'secret.txt'
$ git status
On branch master
Your branch is ahead of 'origin/master' by 10 commits.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    secret.txt

$ git commit -m "secretを削除"
[master b45e12d] secretを削除
 1 file changed, 1 deletion(-)
 delete mode 100644 secret.txt
```
今までのコミットは取り除かれないことを確認する。
```shell
$ git reset
b45e12d (HEAD -> master) secretを削除
b4dfdea secret.txtを作成
$ git reset --hard b4dfdea
作業ツリーを見るとsecret.txtが復活している
```

</details>

## git clone
```
git clone <リモートリポジトリのURL>
git clone <リモートリポジトリのURL> <ディレクトリ名>
```
* リモートリポジトリをローカルへ複製したいときに使用する。
* 第2引数にディレクトリ名を指定するとその名前でローカルに`clone`される。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★☆☆ |
|  危険度    | ☆☆☆☆☆ |
<details open><summary>使用例</summary>

```
$ git clone  https://github.com/ken-hashimoto/example.git
Cloning into 'example'...
remote: Enumerating objects: 34, done.
remote: Counting objects: 100% (34/34), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 34 (delta 5), reused 33 (delta 5), pack-reused 0
Receiving objects: 100% (34/34), done.
Resolving deltas: 100% (5/5), done.
```
</details>

## git remote
```
git remote add <リモート名> <リモートリポジトリのURL>
```
* 手元にあるローカルリポジトリをリモートリポジトリへ対応づけるときに用いる。
* 対応づけられているかどうかは`git remote -v`で確認できる。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★☆☆☆☆ |
|  危険度    | ☆☆☆☆☆ |
<details open><summary>使用例</summary>

```shell
$ git remote -v
origin  https://github.com/ken-hashimoto/example.git (fetch)
origin  https://github.com/ken-hashimoto/example.git (push)
```
</details>

## git fetch
```
git fetch <リモートリポジトリ> <リモートブランチ>
```
* リモートリポジトリの指定したブランチにおける最新のコミット履歴を取得し、リモート追跡ブランチを更新させるために用いる。
* これを実行するとリモート追跡ブランチである`<リモートリポジトリ>/<ブランチ>`が更新されて、リモートと同じ状態を指すようになる。
* これと`merge`を組み合わせることにより、リモートブランチの最新の状態をローカルに取り込みながら開発を進める。

|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ★☆☆☆☆ |
<details open><summary>使用例</summary>

```shell
$ git checkout master
$ git fetch origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), 267 bytes | 9.00 KiB/s, done.
From https://github.com/ken-hashimoto/example
 * branch            master     -> FETCH_HEAD
   bae8150..decb5d5  master     -> origin/master
$ git merge origin/master
Updating bae8150..decb5d5
Fast-forward
 text.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
```
</details>

## git pull
```
git pull <リモートリポジトリ> <リモートブランチ>
```
* 先ほどの「`fetch` + `merge`」を1つのコマンドでできるようにしたものが`pull`


|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ★★★☆☆ |
## git push
```
git push <リモートリポジトリ> <ローカルブランチ>
```
* 指定したローカルブランチで行ったコミット履歴をリモートへ送りたいときに用いる。
* これにより自分の作業成果をリモートへと送ることができるため、共同で開発を行うことができる。


|            |   評価   |
| ---------- | --------- |
|  使用頻度  | ★★★★★ |
|  危険度    | ★★★☆☆ |
<details open><summary>使用例</summary>

```shell
# 作業ブランチへ移動
$ git checkout edit
Switched to branch 'edit'
# ローカルで行った編集をステージし、コミットする。
$ git add .
$ git commit -m "fix typo"
[edit c88392b] fix typo
 1 file changed, 2 insertions(+), 1 deletion(-)
# リモートへpushする。
$ git push origin edit
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 311 bytes | 155.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/ken-hashimoto/git_exer.git
   6848744..c88392b  edit -> edit
```
</details>

# 最後に
最後まで読んでいただきありがとうございました。より詳細な情報を知りたい方は[gitの公式のリファレンス](https://git-scm.com/docs/)をご覧ください。