GitとGithub基礎まとめ

## GitとGithub
### Gitとは
Gitとはバージョン管理システムのこと。自分のPC内（ローカル）で使う。
Gitによってファイルをいつ、誰が、どのように編集したかを履歴に残して管理できる。

### Githubとは
GithubとはGitを使ったホスティングサービスのこと。Githubはインターネット上（リモート）で履歴を管理する。
Githubによって複数人でコードを共有し開発をすることができる。


## Gitの仕組み
Gitはファイルの情報をスナップショットで保存する。スナップショットとは、Gitに追跡されているすべてのファイルのバックアップである。変更の差分を保存しているのではなく、変更前の状態と変更後の状態をそれぞれの履歴として保存しているということである。

このスナップショットのおかげで、前のバージョンに戻したり、差分を計算せずにブランチを切ったり、マージしたりすることが簡単に行える。


## Gitで変更を保存する流れ
1. Gitを初期化する
2. ローカル（自分のPC内）でファイルを変更する
3. ステージングに追加する
4. ローカルリポジトリにコミットする
5. Githubにプッシュする

### 1　Gitを初期化する
まずはGitでバージョン管理したいプロジェクトで`git init`を行う。このコマンドによってGitが初期化され、ローカルリポジトリが作られる。

```
git init
```

リポジトリとは、スナップショットが保存される場所。自分のPC内に作られるリポジトリをローカルリポジトリといい、反対にインターネット上に作られるリポジトリのことをリモートリポジトリという。

ローカルリポジトリは具体的には`.gitディレクトリ`のこと。このディレクトリにGitに必要な情報や履歴が保存される。


### 2　ローカルでファイルを変更する
Gitの初期化が行われたプロジェクトでファイルを作成したり、コードを記述したりする。この作業を行う場所をワークツリーともいう。

### 3　ステージングに追加する
変更を記録する前に`git add`でワークツリーにある変更をステージと呼ばれる場所に追加する。ステージとはコミットする変更を準備する場所のこと。
ステージによって変更した部分だけをコミットすることができる。

```
// ファイルを指定して変更をステージに追加する
git add [ファイル名]

// 変更されているファイルを全てステージに追加する
git add .
```

### 4　ローカルリポジトリにコミットする
ステージにある変更を`git commit`でコミットする。コミットとはスナップショットをリポジトリに保存することである。

```
// CUIのエディタでコミットメッセージを入力する
git commit

// コマンドと一緒にコミットメッセージを入力する
git commit -m "コミットメッセージ"
```

コミットを行う際はコミットメッセージも合わせて記録する。コミットメッセージにはコミットの内容や理由を記述する。

ここまでの作業（変更→ステージに追加→コミット）でローカルリポジトリに変更を記録することは完了する。

### 5　Githubにプッシュする
Githubにローカルリポジトリの内容を保存するには`git push`を使う。Githubにプッシュすることで、他の開発メンバーとコードを共有できる。

プッシュする前に、リモートリポジトリを作成しておく。
```
git remote add origin [URL]
```

originというのはリモートリポジトリのURLのショートカットのようなもの。

リモートリポジトリを作成している状態で、Githubにプッシュする。
```
git push [リモート名] [ブランチ名]

// 2回目のプッシュ以降はgit pushだけでプッシュできるようにするオプション
git push -u origin master
```

## その他のGitの操作
### ファイルの削除を記録する
ファイルの削除を記録するには`git rm`を使う。

```
// ファイルごと削除する
git rm [ファイル名]

// ディレクトリを削除する
git rm -r [ディレクトリ名]

// ワークツリーのファイルを残してリポジトリのファイルは削除する
git rm --cashed [ファイル名]
```

### ファイルの移動を記録する
ファイルの移動を記録するには`git mv`を使う。

```
git mv [旧ファイル名] [新ファイル名]
```


### ファイルの変更を取り消す
ファイルの変更を取り消すには`git checkout --`を使う。`--`がついているのはブランチの切り替えに使う`git checkout`と区別するため。

```
git checkout -- [ファイル名]
git checkout -- [ディレクトリ名]

// 全ての変更を取り消す
git checkout -- .
```

### ステージに追加した変更を取り消す
ステージに追加した変更を取り消すには`git reset HEAD`を使う。ステージの追加を取り消すため、ワークツリーのファイルの変更は残ったままである。

HEADというのは、今自分がいるブランチの最新のコミットを表す。つまりステージに追加された変更を最新のコミットで上書きすることになる。

```
git reset HEAD [ファイル名]
git reset HEAD [ディレクトリ名]

// 全ての変更を取り消す
git reset HEAD .
```

### 直前のコミットを上書きする
直前のコミットを上書きするには`git commit --amend`を使う。

:::note alert
リモートリポジトリにプッシュしたコミットは取り消してはいけない。

プッシュしたコミットを取り消したいときは、新しいコミットを作って修正する。
:::

```
git commit --amend
```

### 直前のコミットを取り消す
直前のコミットを取り消すには`git reset [オプション] HEAD^`を使う。

```
// コミットだけが取り消される（ステージ、ワーキングツリーはそのまま）
git reset --soft HEAD^

// コミットとステージが取り消される（ワーキングツリーはそのまま）
git reset --mixed HEAD^

// コミット、ステージ、ワーキングツリー全て取り消される（）
git reset --hard HEAD^
```

### 特定のコミットを取り消す
特定のコミットを取り消すには`git revert`を使う。

```
git revert [コミットID]
```

revertは新しいコミットを作成して取り消すので、プッシュ済みのコミットに対して使える。resetはコミットそのものを取り消してしまうので、親のコミットを取り消してしまった場合他の開発メンバーがプッシュできなくなる。

### 変更履歴を確認する
変更履歴を確認するには`git log`を使う。

```
git log

// 一行で表示する
git log --oneline

// 変更差分を表示する
git log -p [ファイル名]

// 表示するコミット数を制限する
git log -n [コミット数]
```

### 変更差分を確認する
変更の差分を確認するには`git diff`を使う。

```
// git addする前の変更差分
git diff

// git addした後の変更差分
git diff --staged
```

### 現在の変更状況を確認する
変更されたファイルを確認するには`git status`を使う。このコマンドによって、ワークツリーとステージの間で変更されたファイルと、ステージとリポジトリの間で変更されたファイルを確認する。

```
git status
```

#### ファイルの状態
- 追跡されているかどうか → 新規作成ファイル
- 未修正 → 追跡されていて前回のコミットから変更がない
- 修正済 → 追跡されていて前回のコミットから変更がある
- ステージ済 → ステージに変更が追加されている




### コマンドにエイリアスをつける
エイリアスとはコマンドを省略して入力できるようにしたもの。

```
// PC全体でエイリアスを設定する
git config --global alias.[エイリアス] [gitのコマンド]

// 例
git config --global alias.ci commit
git config --global alias.st status
```

### バージョン管理しないファイルを無視する
パスワードや設定、ログなど外部に公開したくないファイルはGitの管理から外す。

Git管理から外すには.gitディレクトリがあるディレクトリで.gitignoreファイルを作成し、Gitの管理から外したいファイルやディレクトリのパスと名前を記述する。


### ローカルリポジトリを削除する
ローカルリポジトリを削除するには`.git`を削除する。

```
rm -rf .git
```

## Github
### リモートリポジトリを確認する
リモートリポジトリを確認するには`git remote`を使う。

```
// リモート名が表示される
git remote

// リモートのURLが表示される
git remote -v
```


### リモートリポジトリを追加する
リモートリポジトリを追加するには`git remote add`を使う。

リモートリポジトリはチーム開発とは別で個人のリポジトリをもっておきたいときなど複数登録できる。

```
git remote add [リモート名] [リモートURL]
```

リモート名には`origin`という名前がよく使われる。これはGitがデフォルトで指定しているリモートリポジトリの名前である。

リモート名を指定することでリモートリポジトリに対して操作するときにURLを指定する必要がなくなる。


### リモートリポジトリから情報を取得する
リモートリポジトリから情報を取得するにはクローン、フェッチ、プルの3つの方法がある。

#### クローン
クローンは最初だけリモートリポジトリの内容をローカルに取得するときに使う。フェッチとプルは都度情報を取得するときに使うもの。

```
git clone [リモートリポジトリのURL]
```

#### フェッチ
フェッチを行うとリモートリポジトリから情報を取得し、ローカルリポジトリの追跡ブランチに保存される。フェッチするには`git fetch`を使う。取得した情報はワークツリーには反映されないので、反映したいときは`git merge`を使ってマージする。

```
git fetch [リモート名]
```

#### プル
プルを使うと、フェッチ→マージの2つのコマンドを1つで行うことができる。

```
git pull [リモート名] [ブランチ名]
```

#### フェッチとプルの使い分け
基本的にはフェッチを使う。プルを使うと、今いるブランチに取得した情報がマージされるので注意する。

フェッチ → リモートから情報を取得するだけ
プル → リモートから情報を取得し、ワークツリーに反映する（fetch + merge）

### リモートリポジトリの詳細情報を表示する
リモートリポジトリの詳しい情報を知りたいときは`git remote show`を使う。

```
git remote show [リモート名]
```

表示される詳細情報
- fetchとpushのURL
- リモートブランチ
- git pullの挙動
- git pushの挙動

### リモートリポジトリを変更する
リモートリポジトリを変更するには`git remote rename`を使う。

```
git remote rename [旧リモート名] [新リモート名]
```

### リモートリポジトリを削除する
リモートリポジトリを削除するには`git remote rm`を使う。

```
git remote rm [リモート名]
```


## ブランチとマージ
### ブランチとは
ブランチとは、並行して複数の機能を開発するための仕組み。ブランチを使うことで他の人の変更の影響を受けなくなる。


### ブランチの種類
ブランチには3つの種類がある。

#### ローカルブランチ
ローカルブランチはローカルで作成するブランチ。ローカルリポジトリを作成したときには自動的にローカルにmain(master)ブランチが作成されている。

#### リモートブランチ
リモートブランチはリモートに存在するブランチ。リモートブランチを作成するには`git push`で行う。

```
git push -u [リモート名] [ブランチ名]
```

#### 追跡ブランチ
追跡ブランチはリモートブランチを追跡するブランチのこと。追跡ブランチはリモートではなくローカルにある。

`git branch -a`で表示される`remote/[リモート名]/[ブランチ名]`が追跡ブランチのこと。

`git fetch`を行ったときに、リモートブランチの内容で追跡ブランチの内容を更新する。
`git pull`だと追跡ブランチを今いるブランチにマージするところまで行われる。

リモートブランチの内容で更新された追跡ブランチをマージすることによってリモートブランチの内容をワークツリーに反映することができる。


### ブランチの仕組み
ブランチは最新のコミットを指し示す参照である。

ブランチにはブランチ名をもつファイルがあり、その中にブランチごとの最新のコミットファイル名が記載されている。

ブランチの仕組みを理解するためには、コミットの仕組みとHEADを理解する必要がある。

#### コミットの仕組み
コミットは直前のコミットの情報を持っており、それによって履歴を辿ることができる。

ブランチは新しくコミットを行うとそのコミットを指し示すようになる。


#### HEAD
HEADは今自分が作業しているブランチを指し示す。他のブランチで作業したい時にはこのHEADを移動させることでブランチを切り替える。

HEADの中身は、今作業しているブランチの名前が記載されている。

HEADを移動させるとブランチが切り替わり、そのブランチでコミットを行うことで開発が分岐されていく。

### ブランチを切る
新しいブランチを作成することをブランチを切るといい、`git branch`を使う。`git branch`はブランチを作成するだけでブランチの切り替えは行わないので、HEADは元々いたブランチを指している状態のままである。

```
// ブランチを作成する
git branch [ブランチ名]

// ブランチ名を入力しないとブランチの一覧を表示する
git branch

// 追跡ブランチも合わせて表示する
git branch -a
```

:::note
最初のコミットを行うと`master`という名前のブランチが作成される。
最近は`master`ではなく`main`という名前が使われる。
:::

### ブランチを切り替える
ブランチを切り替えるには`git checkout`を使う。ブランチを切り替えるとHEADが切り替えたブランチを指すようになる。これによって別々の機能を並行して作ることができるようになる。

```
git checkout [ブランチ名]

// ブランチを作成し、そのブランチに切り替える
git checkout -b [ブランチ名]
```

### ブランチ名を変更する
ブランチ名を変更するには`git branch -m`を使う。

```
// 今作業しているブランチ名を変更する
git branch -m [ブランチ名]
```

### ブランチを削除する
ブランチを削除するには`git branch -d`を使う。

```
// マージされていないブランチは削除できない
git branch -d [ブランチ名]

// 強制削除する
git branch -D [ブランチ名]
```


### 変更をマージする
マージとは、他の人の変更内容を自分が今いるブランチに取り込むこと。マージを行うと2つのブランチを統合した新しいコミットが作成される。

マージするには`git merge`を使う。

```
git merge [ブランチ名]
git merge [リモート名/ブランチ名]
```

マージには3種類ある。
- ファストフォワード
- オートマージ
- コンフリクト

#### ファストフォワード
片方のブランチはコミットを行い、もう片方のブランチがコミットをしていない（ブランチが分岐していない）ときにマージすること。このときブランチは最新のコミットのほうに参照を進める。

#### オートマージ
基本のマージ。別々のブランチでコミットを行い、それらのブランチをマージすること。このときマージコミットが作成される。マージコミットは2つの親コミットを持つ。

#### コンフリクト
コンフリクトとは、同じ箇所の異なる変更をマージした時にGitがどっちの変更を優先していいかわからない状態のこと。
コンフリクトが起きている状態で`git status`を実行すると、`both modified`と表示される。

コンフリクトを解決するには、最終的なファイルの内容に書き換えること。

コンフリクトを起こさないように複数人が同じ箇所を変更しないように気をつける。


## Githubを利用した開発手順の流れ
### プルリクエスト
プルリクエストとは、自分が変更したコードをリポジトリに取り込んでもらうよう他の開発メンバーに依頼する機能のこと。コードを取り込む前に、バグを防いだり、コードの質を担保するためのレビューを行う必要がある。そのレビューを依頼するのがプルリクエスト。

プルリクエストは以下の手順で行う。
1. ローカルのmainブランチを最新に更新する
2. ローカルブランチを作成する
3. ファイルを変更する
4. 変更をコミットする
5. Githubへプッシュする
6. プルリクエストを送る
7. プルリクエストを受けた人がレビューを行う
8. レビューがOKであればプルリクエストをGithubのmainブランチにマージする
9. マージが終わればリモートブランチを削除する
9. ローカルブランチも削除する

### Github Flow
Github Flowとは、Githubを利用した開発の方法の1つ。mainブランチから開発用のブランチを作成し、新しい機能の開発は開発用のブランチで行うためとてもシンプル。

Github Flowは以下の流れで開発する。
1. mainブランチから開発ブランチを作成
2. ファイルを変更し、コミットする
3. Githubに変更をプッシュする
4. プルリクエストを送る
5. 承認されればmainブランチにマージする
6. mainブランチを本番環境にデプロイする

mainブランチは常にデプロイできる状態を保ち、開発用のブランチは他の開発者が開発状況を把握できるようにするため定期的にプッシュすることが重要。

## リベース
リベースとは、ブランチを統合する

```
git rebase [ブランチ名]
```

### リベースとマージの違い
コミットの履歴を綺麗にしたいならリベースを使い、コミットの履歴を残したいならマージを使う。

### リベースとプル
プルする時にもマージとリベースの違いがある。

```
// マージコミットが残る
git pull [リモート名] [ブランチ名]

// マージコミットが残らない
git pull --rebase [リモート名] [ブランチ名]
```

### リベースの注意点
Githubにプッシュしたコミットをリベースしてはいけない。

## タグ
タグとはコミットを参照しやすくするために名前をつけること。いつリリースしたかやどのバージョンかを示すためにつけられることが多い。

### タグの一覧を表示する
タグの一覧を表示するためには`git tag`を使う。

```
git tag
```

### タグを作成する
タグを作成するには`git tag`にタグ名をつける。タグには軽量版タグと注釈付きタグの2種類ある。

軽量版タグはタグの名前だけをつける。
注釈付きタグにはタグをつけた人の名前やコメントをつけることができる。

```
// 軽量版タグを作成する
git tag [タグ名]

// 注釈付きタグを作成する
git tag -a [タグ名] -m [メッセージ]

// 後からタグをつける
git tag [タグ名] [コミット名]
```

### タグの詳細情報を確認する
タグの詳細情報を確認するには`git show`にタグ名を使う。これによってタグをつけた人の情報、タグをつけた日時、注釈メッセージ、コミットの情報を確認することができる。

```
git show [タグ名]
```

### タグをリモートリポジトリに送信する
タグをリモートリポジトリに送信するには`git push`を使って別途で指定する。

```
// 任意のタグをリモートに送信
git push [リモート名] [タグ名]

// 全てのタグをリモートに送信
git push [リモート名] --tags
```

## スタッシュ
スタッシュとは、作業の途中でコミットしたくない時に別のブランチに移動するために作業を一時避難すること。

### 作業を一時避難する
スタッシュするには`git stash`を使う。変更分をstashに保存することで、変更を無かったことにする。

```
git stash
```

### 避難した作業を確認する
避難した作業を確認するには`git stash list`を使う。

```
git stash list
```

### 避難した作業を復元する
避難した作業を復元するには`git stash apply`を使う。

```
// 最新の作業を復元する
git stash apply

// 特定の作業を復元する
git stash apply [スタッシュ名]

// ステージの状況も復元する
git stash apply --index
```


### 避難した作業を削除する
避難した作業を削除するには`git stash drop`を使う。

```
// 特定のスタッシュを削除する
git stash drop [スタッシュ名]

// 全てのスタッシュを削除する
git stash clear
```


## まとめ
- Gitはバージョン管理を行うためのツール
- Gitは変更を差分ではなくスナップショットで保存し、そのスナップショットを辿ることで履歴を管理したり、ブランチを作成したりすることができる
- 変更を保存するにはステージに追加してコミットする
- Githubに変更を保存するにはローカルリポジトリにコミットしたものをプッシュする
- Githubからデータを取得するにはフェッチとプルの2つの方法があり、フェッチは取得するだけでマージせず、プルは取得してマージも行う
- 並行して別々の機能を作りたいときはブランチを作って分岐する
- ブランチは最新のコミットを指す参照である


## 参考
https://github.com/kaityo256/github/blob/main/internals/README.md
[Git： もう怖くないGit！チーム開発で必要なGitを完全マスター](https://www.udemy.com/course/unscared_git/)
https://www.r-staffing.co.jp/engineer/archive/category/%E3%83%9E%E3%83%B3%E3%82%AC%E3%83%BBGit