CI/CDをkatacodaで体験（初心者向け） - Part4(Undoing Changes)

# CI/CD入門
このぺーじでは、[katacoda](https://www.katacoda.com/)と呼ばれる「ブラウザから無料で勉強用のインスタンスを起動できるWebサービス」を利用してCI/CDを実践します
内容は上記リンクに沿うので、不明点があればそちらへどうぞ

## Gitのバージョン管理について - Scenario4 - Undoing Changes
ここでは、CI/CDとして欠かせないGitによるバージョン管理について学習します
このシナリオで学習することをさっと確認する場合は**概要**を確認
**理解に間違い等がございましたら、ぜひご指摘ください**

### <font color="Red">概要</font>
>- ```git checkout```でワーキングディレクトリの状態を前回コミット時（変更前）に戻す
- ```git reset```でステージングの状態をワーキングディレクトリの状態（```git add```する前）に戻す
- ```git reset```時にオプションとして```--hard```を利用することで、ステージングの状態（```git checkout```+```git reset(オプションなし)```）を前回コミット時に戻す
- ```git revert```で、前回あるいは、複数回前のコミット状態に戻す
- どのbranchに対して戻すのかcommit hash（基本的には```HEAD```）を指定したほうが間違いが少ない

### Step 1 - Git Checkout
```git checkout```はbranchの変更時に利用されるコマンドだが、編集中のワーキングディレクトリを前回コミット時の状態に戻すことも可能
状態が戻ったことは、```git status```で確認可能

```
$ ls -a
.  ..  committed.txt  .git  staging.txt
$ git branch
* ESC[32mmasterESC[m
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   staging.txt

no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout .
$ ls -a
.  ..  committed.txt  .git  staging.txt
$ git branch
* ESC[32mmasterESC[m
$ git status
On branch master
nothing to commit, working tree clean
```

### Step 2 - Git Reset
Step1では、**ワーキングディレクトリ上にファイルがある状態->前回コミット時の状態**に戻す操作
Step2では、**ステージング上にファイルがある状態->ワーキングディレクトリ上にファイルがある状態**へと戻す操作
```git reset <file/directory>```で、実行可能

```
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   staging.txt

$ git branch -a
* ESC[32mmasterESC[m
$ git reset HEAD .
Unstaged changes after reset:
M       staging.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   staging.txt

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

>**HEAD とは**
```HEAD```とは端的に言うと、**「現在、作業しているブランチのバージョンを指定するもの」**
そのため、下記ソースコードのように```git reset HEAD .```のように記述しなくても今回は問題ありません

```
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   staging.txt

$ git reset .
Unstaged changes after reset:
M       staging.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   staging.txt

no changes added to commit (use "git add" and/or "git commit -a")
```
>では、なぜ```HEAD```が必要か？
作業しているbranchと異なるbranchに対して、何らかの操作を加えたり、以前のバージョンに対して操作を加える際に```commit hash```を指定する必要があります
作業しているbranchが最新のバージョンであれば、```commit hash```に```HEAD```を利用し、そうでないなら、適切な```commit hash```を選択
詳しくは[こちら](https://qiita.com/ymzk-jp/items/00ff664da60c37458aaa#:~:text=HEAD%E3%81%8C%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E4%BB%A5%E5%A4%96%E3%81%AE,detached%20HEAD%E3%81%A8%E5%91%BC%E3%81%B3%E3%81%BE%E3%81%99%E3%80%82)

### Step 3 - Git Reset Hard
step3では、step1,2の操作を一度に行う
それを確かめるため、```staging.txt```はステージング上に、```commited.txt```はワーキングディレクトリ上に存在させる
その後、```git reset --hard```によって二つのファイルを前回コミット時へ戻す

```
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   staging.txt

$ cat committed.txt
Committed File
$ echo 'test' >> committed.txt
$ cat committed.txt
Committed File
test
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   staging.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   committed.txt

$ git reset --hard HEAD
HEAD is now at 5d62819 New File
$ git status
On branch master
nothing to commit, working tree clean
$ cat committed.txt
Committed File
```

### Step 4 - Git Revert
続いて学習するのは```git revert```
これは、誤ってコミットした場合に利用
**commit_v0(前回の状態) -> commit_v1(間違い) -> git revert （HEAD）  -> commit_v0(前回の状態)**
```git revert```はオプションとして、コメント（```git commit -m```で用いるコミットメントコメント）を付与したりしなかったりできる
ログを残すことで後々確認しやすいので、オプションとして``-e/--edit``を用いる方が良い
>その他のオプション
-e/--edit : コミットコメント書き込み
--no-edit : コミットコメントなし（前回のコミットコメント利用）
-n/--no-commit : コミットの取り消し（ステージングへの巻き戻し）
[参考リンク](https://qiita.com/chihiro/items/2fa827d0eac98109e7ee)

```
$ git log
ESC[33mcommit 676354469da2eff5cf7df1df0f17ba8183ce5bbeESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[
Author: Katacoda Scenario <scenario@katacoda.com>
Date:   Wed Oct 14 00:03:04 2020 +0000

    Commit To Revert

$ git revert HEAD -e   //"-e"オプションでeditorが表示される。適当なコメントを入力
[master 3240f2b] Revert "Commit To Test Revert"
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log
ESC[33mcommit 3240f2b8b0a87363ed07fac7ade4a4c267e52bbdESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[
Author: Katacoda Scenario <scenario@katacoda.com>
Date:   Wed Oct 14 00:06:56 2020 +0000

    Revert "Commit To Test Revert"

    This reverts commit 676354469da2eff5cf7df1df0f17ba8183ce5bbe.

ESC[33mcommit 676354469da2eff5cf7df1df0f17ba8183ce5bbeESC[m
Author: Katacoda Scenario <scenario@katacoda.com>
Date:   Wed Oct 14 00:03:04 2020 +0000

    Commit To Revert
```

上の結果から分かる通り、logには新しく"Commit To Test Revert"と表示されている

**注意**
```git revert```はステージングやワーキングディレクトリに対しては、何も操作しない

```
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   index.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   working.txt

$ git revert HEAD --no-edit
error: your local changes would be overwritten by revert.   //commitされていない修正のため、エラー
hint: commit your changes or stash them to proceed.
fatal: revert failed
```

### Step 5 - Git Revert
step4では、一つ前のコミットに戻していたが、二回以上前のコミットに戻すことも可能
現在の状態からいくつ前に戻るかは```git revert HEAD...HEAD~(n)```のように指定

```
$ cat test.txt
test
2
3
4
$ gi add test.txt
bash: gi: command not found
$ git add test.txt
$ git commit -m 'fours commit'
[master c3d82f1] fours commit
 1 file changed, 1 insertion(+)
$ git log --oneline
ESC[33mc3d82f1ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[1;32mmasterESC[mESC[33m)ESC[m fours commit
ESC[33m909ad91ESC[m third commit
ESC[33m1cb550cESC[m second commit
ESC[33m0062e56ESC[m first commit
ESC[33m1d059eaESC[m Revert "Commit To Revert"
ESC[33m12fcca9ESC[m Revert "Revert "Commit To Revert""
ESC[33md5aa2f3ESC[m Revert "Commit To Revert"
ESC[33m3d950a6ESC[m Commit To Revert
ESC[33m88e2869ESC[m New File
ESC[33m43250bfESC[m Fixing Error
ESC[33m22457e2ESC[m First Commit
$ git revert HEAD...HEAD~2
[master 7dec1c4] Revert "fifth commit"
 1 file changed, 1 deletion(-)
[master 05804a9] Revert "third commit"
 1 file changed, 1 deletion(-)
$ git log --oneline
ESC[33m05804a9ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[1;32mmasterESC[mESC[33m)ESC[m Revert "third
ESC[33m7dec1c4ESC[m Revert "fifth commit"
ESC[33mc3d82f1ESC[m fours commit
ESC[33m909ad91ESC[m third commit
ESC[33m1cb550cESC[m second commit
ESC[33m0062e56ESC[m first commit
ESC[33m1d059eaESC[m Revert "Commit To Revert"
ESC[33m12fcca9ESC[m Revert "Revert "Commit To Revert""
ESC[33md5aa2f3ESC[m Revert "Commit To Revert"
ESC[33m3d950a6ESC[m Commit To Revert
ESC[33m88e2869ESC[m New File
ESC[33m43250bfESC[m Fixing Error
ESC[33m22457e2ESC[m First Commit
$ cat test.txt
test
2
```

上記の結果の通り（分かりやすさのため、katacodaと異なる手順で確認してます）、```test.txt```は一行ずつコミットを行い、4回目のコミット後に```git revert```として5回目のコミットを実行
結果、二つ前の状態に遷移