このコマンドを知っていれば作業はできる????っていうGitコマンドをまとめてみる

大半の企業や開発では、みなさんGitやGitHubを使っていると思います。

ですが、開発学びたての頃とかはあまり使い方がわからなかったりして、友達とハッカソンを出るときに困ったりすることが多いと思います。

今回は、個人の見解ではありますがこのコマンドを知っていれば作業ができるのではないかというGitの基本的なコマンドをまとめてみようと思います。

# そもそもGitとは
Gitは、分散型バージョンシステムと呼ばれるものです。
ソースコードをのバージョンを管理して簡単に戻したり、複数のバージョンを確保して並行で進めたりと開発を効率化させるために生まれました。

# Githubとの違いは？
Githubは、インターネットを介してGitで管理しているソースコードやデザインなどを共有することのできるwebサービスです。

Gitはローカルデバイス（自身のパソコン等)で管理するのに対して、Githubはインターネット上で管理できるという違いがあります。

# Gitコマンド一覧
Gitの操作はCLI上でコマンドで行います。

SourceTreeなどGUIで操作することもできますが、個人的にはコマンドの方が問題解決に関する情報が多いので、コマンドに慣れておくことをお勧めします。

## リポジトリの初期化

リポジトリの初期化の前にまず`cd`コマンドでGitに反映させたいプロジェクトのルートディレクトリに移動します。

その位置でinitコマンドをすることでgitリポジトリを初期化することができます。

```zsh:git
git init
```
`init`コマンドを使った現在いるディレクトリ（作業ディレクトリ)に`.git`が作成されます。
`.git`ディレクトリにはgitのメタデータが入っており、それがリポジトリの役割を担うことになります。
新しいブランチ(mainブランチ)も作成されます。

:::note

### ベアリポジトリとノンベアリポジトリとは
ドキュメントを読むとベアリポジトリとノンベアリポジトリという用語が出てきます。
ベアリポジトリとノンベアリポジトリの違いは、作業ディレクトリがあるかどうかになっています。

|リポジトリ|作業用ディレクトリ|用途
|---|---|---
|ベアリポジトリ|なし|更新管理用
|ノンベアリポジトリ|あり|作業用ディレクトリ

Githubで作成するリモートリポジトリはベアリポジトリ
initコマンドで作成するローカルリポジトリはノンベアリポジトリに当たります
:::


## ローカルリポジトリのファイル状況を確認する
リポジトリで管理しているファイルは状態が付与されます。

まずファイルには、untrackedとtrackedという状態があります。
これはリポジトリがそのファイルを追跡しているか(管理しているかを表しています。

そこからtrackedにはUnmodified,Modified,Stagedの3つ状態があります。

|状態|意味
|---|---
|Untracked|未追跡のファイル
|tracked|追跡済みのファイル
|Unmodified|追跡済みかつ変更されていない
|Modified|追跡済みかつ変更されている
|Staged|ステージされている|

これらを確認するにはstatusコマンドを使います。

```zsh:git
git status
```

初期状態では、このようになっておりファイルには何もない状態と表示されます。
```zsh:zsh
nothing to commit, working directory clean
```

もしファイルに変更があれば下のように表示されます。
表示されているようにREADMEという`Untracked`、未追跡のファイルがあることがわかります。
```zsh:zsh
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README

nothing added to commit but untracked files present (use "git add" to track)
```


もし`tracked`のファイルを修正していた場合は下のように表示されます。
```zsh:git
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:   CONTRIBUTING.md
```


## ファイルをステージングする

`Untracked`を`Tracked`に変える、`Modified`でステージングされていないものはaddコマンドで`staged`に持っていきます。
このことをステージングと言います。

とは言ってもステージングはわかりにくいと思います。

ステージングは、コミット前にコミットする対象を選ぶことと認識すると良いと思います。

addコマンドは下のように使います。

```zsh:git
git add <file_path>
```

ここでstatusコマンドで状態を表示すると、もし`Untracked`を`Tracked`に変えた場合は下のように表示されます。
```zsh:zsh
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
```


`Tracked`であったファイルをステージングすると下のようになります。
```git:zsh
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md
```

:::note
### `git add .`は無闇に使わない
下のコマンドで全ての変更ファイルをステージングできます。

```zsh:git
git add .
```

非常に便利ですが、意図しないファイルをステージングしてしまうので、無闇に使わないようにしましょう。
:::

## 変更の差分を見る
diffコマンドで、ステージされていないファイルの変更した部分を確認することができます。

```zsh:git
git diff
```

すると下のように変更されたファイルは`+++`、元のファイルの状態は`---`と表示されます。

```
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
```

ステージされているものを見る場合は下のコマンドになります。

```zsh:git
git diff --staged
```

## 変更のコミット

先ほど出てきたコミットという動作をするにはcommitコマンドを使います。

```zsh:git
git commit -m "message"
```

-mはコメントをつけるオプションです。

:::note
### -mをつけなかった場合

もしコメントをつけずにcommitした場合は下のようにエディタが立ち上がってしまいます。
```
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C
```

エディタを立ち上げるよりは-mでコメントを書いてしまった方が早いので、-mで書いてしまいましょう。
:::

-aをつけることで、addコマンドを省略してコミットすることもできます。

```zsh:git
git commit -m -a "message"
```
非常に便意なコマンドですが、変更したファイルを全てステージに持っていってしまうため、意図しないファイルを追加する可能性があります。

できるだけ、addコマンドでファイルを指定しましょう。

## リポジトリからファイルを削除

リポジトリかつ作業ディレクトリからファイルを削除したいときは、rmコマンドで削除します。

```zsh:git
git rm <file_name>
```

作業ディレクトリには残したい場合は`--cached`を使います。
```zsh:git
git rm --cached <file_name>
```
このコマンドは間違えて`.vscode`や`.ida`など、エディタの設定ファイルや、`.env`などのリポジトリに含めたくないファイルをステージングやコミットしてしまった時に使います。

:::note
### rmを使わないために

`.gitignore`でファイルを無視することも可能です。

下のようにルートディレクトリに下のように記述したら`.env`は無視されます。

```.gitignore
.env
```

:::

## ブランチの一覧・作成・削除

ブランチの一覧・作成・削除はbranchコマンドを使います。

- ローカルブランチ一覧
```zsh:git
git branch
```

- リモートブランチ一覧
```zsh:git
git branch -r
```

- 全てのブランチ一覧

```zsh:git
git branch -a
```

- 作成
```zsh:git
git branch <branch_name>
```

- 削除
```zsh:git
git branch -D <branch_name>
```

## ブランチの変更・作成

ローカルリポジトリにおいてブランチの移動をするにはswitchコマンドを使用します。

```zsh:git
git switch <branch_name>
```

ブランチの作成には-cオプションで行うことができます。
```zsh:git
git switch -c <branch_name>
```

:::note
### checkoutとswitchの使い分け
switchで行える作業は、元々checkoutで行っていました。

ただ、checkoutは作業ディレクトリをリセットしたり、コミット履歴を戻したりなど色々な操作が必要になるため、かなりややこしいコマンドになってしまっていました。

これを解決するためにブランチの移動をswitchが作られました。

なので、できるだけブランチの移動はswitchで行いましょう。

:::

## 別ブランチと現在のブランチを結合する(マージ)

別ブランチにあるコードと現在にあるブランチにいい感じに反映させたいとなった場合は、mergeコマンドを使います。

```zsh:git
git merge <branch_name>
```

mergeには種類が3つほどあります。

1つは、`fast forward`で親ブランチの先に派生ブランチのコミットがやってきます。

これは、親ブランチから派生した後、親ブランチの変更が何もない場合に簡単にfeatureブランチの取り込みが行える時に起きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/576b3c71-eb2c-427a-1dcf-939fac23cb34.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/98e8f304-3002-bf5c-02d8-5d0824f2e535.png)

2つ目は、Automergeです。
二つのブランチが同時刻において別々の変更があった場合に、両方のブランチのコミットを取り込むことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/424041c1-64ea-7268-0b30-a82f392af5b7.png)


3つ目は、conflictです。
上で紹介したautomergeを行った場合に、変更差分が重複してGitがよしなにコミットを取り込めない状態を指します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/c592d1bb-6ae6-a307-c3f4-2e9ed9744ccf.png)


## リモートリポジトリを設定
Githubなどのリモートリポジトリにローカルリポジトリの状況を反映させるために、ローカルリポジトリにリモートリポジトリの情報を設定します。

remote addコマンドを使って設定します。
```zsh:git
git remote add <repo_URL>
```

リモートリポジトリのURLは、Githubのソースコードが確認できるリポジトリのページの下のところから確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/14043e09-9c6b-06c9-184b-c46da48d8d81.png)


## リモートリポジトリにプッシュ

Githubなどのリモートリポジトリにデバイス上にあるローカルリポジトリの内容を反映させるには、pushコマンドを使います。

```zsh:git
git push <remote_repository> <branch_name>
```

例えばoriginと登録したリモートリポジトリのmainブランチにpushするには下のように行います。
```zsh:git
git push origin main
```

## リポジトリをクローンする
共同開発する場合は代表の人がリポジトリを作成してGithubにあげる、そしてそれを自分のローカルのパソコンに持ってくるという作業が必要になります。ローカルのパソコンにリモートリポジトリを持ってくることをクローンと言います。

クローンは下のコマンドで行います。

```zsh:git
git clone <repo url>
```

URLは`HTTPS`や`SSH`などあります。

:::note
### HTTPSって？
HTTPを使った通信をSSLやTLSといった暗号方式を使って、通信を暗号化する通信プロトコル(方法)のことです。
:::

:::note
### SSHって?
手元にないリモート上のコンピューターと接続するためのプロトコルをSSHと言います。
Gitでは、公開鍵暗号認証を行うことで、安全に通信することができます。
:::

## リモートリポジトリの状態を持ってくる(フェッチ)
リモートリポジトリのデータを持ってくるにはfetchコマンドを使います。

これをすることでリモートリポジトリのブランチの情報やリモートとの差分を確認するようにできるようになります。

```zsh:git
git fetch
```

## リモートリポジトリのコードをプルする

リモートのリポジトリをブランチをフェッチして、マージするにはpullコマンドを使います。

```zsh:git
git pull origin <ブランチ名>
```

:::note
### ここで注意したほうがいいこと

経験則ではありますが、なるべくfetchコマンドを打ってからcloneしたほうがいいと思っています。

cloneしたのに何故かリモートリポジトリの状況と一緒にならないということが起きたりします。

なのでできるだけfetchしてからcloneするようにしましょう。
:::

# ケース一覧

先ほどあげたコマンドで実際にどのように操作していくのかをケース毎に紹介したいと思います。

全てのケースを網羅はできておらず先ほど紹介したコマンドの中でも使ってないものもありますが、参考にしていただきたいです。

## 個人でリポジトリを作って管理する場合

Githubでリポジトリを作成する。
↓
リポジトリをinitコマンドで作成する
```zsh:git
git init
```
↓
remote addでリモートリポジトリを追加する
```zsh:git
git remote add <url>
```
↓
addコマンドを使って現在の状態をステージング
```zsh:git
git add <file>
```
↓
commitコマンドでローカルリポジトリに反映
```zsh:git
git commit -m "messageを書く"
```
↓
pushコマンドでリモートリポジトリに反映
```zsh:git
git push origin <branch>
```

## 共同開発で管理する場合

### リモートブランチをクローンして作業
GithubからリポジトリのURLをメモする
↓
cloneコマンドでクローンする
```zsh:git
git clone 
```
↓
switchコマンドでブランチを分ける
```zsh:git
git switch -c feature/<name>
```
↓
作業する
↓
addコマンドを使って現在の状態をステージング
```zsh:git
git add <file>
```
↓
commitコマンドでローカルリポジトリに反映
```zsh:git
git commit -m "messageを書く"
```
↓
pushコマンドでリモートリポジトリに反映
```zsh:git
git push origin <branch>
```
↓
GithubでPRを作成して統合用ブランチ(mainとかdevelop)にマージする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/23abaed7-6f3b-ff8d-85bb-f6b2256a69d5.png)
↓
統合用ブランチに移動する
```zsh:git
git switch <branch_name>
git fetch
```
↓
統合内容を反映する
```zsh:git
git pull origin <branch_name>
```

### 統合用ブランチの状態を作業ブランチにマージする
上記で作業しているときに統合用ブランチに入った変更を現在の作業ブランチに持ってきたい時のケースを紹介します。（コンフリクトは起きてない前提です)

統合用ブランチに最新の情報を引っ張ります。
```zsh:git
git fetch
```
もしくはローカルの統合用ブランチにpullします。
```zsh:git
git switch <branch_name>
git pull origin <branch_name>
```
↓
`作業ディレクトリにいる状態`でマージします。branch_nameには統合用ブランチを指定します。
- ひとつ前でfetchを使った場合
```zsh:git
git merge origin/<branch_name>
```
- ひとつ前で統合用ブランチにリモートの状態を反映させた場合

```zsh:git
git merge <branch_name>
```

# まとめ

コマンド一覧は以下のようになっています。

|コマンド|機能
|---|---
|add|ファイルをステージング
|status|変更のあるファイルを確認
|branch|ブランチの一覧・作成・削除
|switch|ブランチに移動と作成
|merge|いい感じにブランチを結合
|rm|ファイルをリポジトリから削除
|remote add|リモートリポジトリのURLを設定
|push|リモートリポジトリに反映
|clone|リモートリポジトリを持ってくる
|fetch|リモートリポジトリの状況を持ってくる
|pull|リモートリポジトリの状況を反映