Gitの基本 - git cloneからgit pushとブランチの削除まで

## この記事について
* Gitを使用した開発の一連の流れを説明します
* 「これを知っていれば基本的な開発は行える！」というレベルの内容を記載しており、「コミットを取り消したい」「Gitの設定内容を変更したい」などより詳細な内容は本記事では扱っておりません

## 対象読者
* Gitを使用して開発を始めたい方
* Gitの基本的な使い方を一通り学びたい方

## Gitにおける2つのリポジトリ（リモートリポジトリとローカルリポジトリ）
Gitで使用するコマンドを説明する中で`リモートリポジトリ`と`ローカルリポジトリ`という言葉を使いますので、まずはこの2つの言葉について説明します。
基本的な概念を説明しており、細かい点までは記載できておりませんので、ざっくりとこんな感じでGitでソースが管理されていると理解いただければと思います。

### リポジトリの全体像
Gitではソースの履歴管理をサーバ上の**リモートリポジトリ**と自分のPC上の**ローカルリポジトリ**に分けて行っております。（分散型バージョン管理システム）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/92310360-f368-113e-1880-84d4009e5518.png)

### リポジトリとは
Gitに限ったことではないですが、バージョン管理システムにおける**リポジトリ**とは、**バージョン管理を行う対象のファイルやディレクトリを入れるための場所**です。
（英語の`repository`の直訳が`収納場所`であることからもこのイメージが付きやすいかと思います）

### リモートリポジトリとは
あるサーバ上に作成・管理され、開発チーム全員が共有しているリポジトリです。
参考：[リモートでの作業](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%81%A7%E3%81%AE%E4%BD%9C%E6%A5%AD)

### ローカルリポジトリとは
各開発者のPC上（ローカル環境）で作成され、そのローカル環境でのみ管理されるリポジトリです。
**自分が行ったソースの変更が他の開発者に影響を与えることなく**また**他の開発者が行ったソースの変更で自分が影響を受けることなく**ソースの履歴管理を行えます。

ローカルリポジトリで変更した内容は、リモートリポジトリに反映（後述）しない限りはリモートリポジトリに反映されませんし、
リモートリポジトリで変更した内容は、ローカルリポジトリに取込（後述）をしない限りはローカルリポジトリに反映されません。

### リポジトリがリモートとローカルで別れていることのメリット
* ローカルリポジトリでは自分が開発を行いやすいようにブランチ分けを行ったり、好きなタイミングでコミット・マージを行うことが可能です  
（`Subversion`など集中型バージョン管理システムでは、自分のコミットが即座にリモートリポジトリにも反映されるため、部分的にコミットなどが行いづらくなります）
* リモートリポジトリ（サーバ）に接続していない状態でもコミット可能なため、開発環境の制約を抑えることもできます  
（集中型バージョン管理システムでは、リモートリポジトリのサーバに接続していない限りはコミットが行えないため、開発環境に制約が生まれてしまいます）

## Gitでの開発流れ
ここからはGitを使用した開発の流れを説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/e9288a1b-5cea-5e69-6b4f-4b8a3674616c.png)

この画像の内容を以下の手順で説明します。
[Git](https://git-scm.com/downloads)はインストール済みとします。

1. リモートリポジトリからローカルリポジトリを作成（コピー）
1. ローカルリポジトリでブランチを作成
1. ローカルの変更をステージング
1. コミット
1. ローカルリポジトリの変更をリモートリポジトリに反映
1. リモートリポジトリの変更をローカルリポジトリに取込
1. ブランチの削除（機能開発の終了後に行う）

### リモートリポジトリからローカルリポジトリを作成（コピー）
サーバ上にあるリモートリポジトリを取得して、ローカルリポジトリを作成します。
ローカル環境でコマンドを実行したディレクトリの直下に、物理的にディレクトリが作成されます。
#### リモートリポジトリへの接続方法が`https`の場合
```
git clone https://[ホスト名またはIPアドレス]/[グループ]/[リポジトリ].git
```
`example.com`上にグループ`sample`のリモートリポジトリ`test`が存在する場合

```
git clone https://example.com/sample/test.git
```
通常、画像のGitHubの例のようにリモートリポジトリ側でリポジトリのURLが表示されるため、そのURLをコピーして指定すると良いかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/0e76a5ed-dc81-b505-438b-ea8a95fbe643.png)

#### リモートリポジトリへの接続方法が`ssh`の場合
（事前にSSH接続用の鍵を生成・登録してください。参考：[Github使用時の例](https://docs.github.com/ja/github/authenticating-to-github/connecting-to-github-with-ssh/checking-for-existing-ssh-keys)）

```
git clone ssh://git@[ホスト名またはIPアドレス]/[グループ]/[リポジトリ].git
```

### ローカルリポジトリでブランチを作成
`feature/#1`ブランチを作成して、作成した`feature/#1`ブランチに移動

```
git checkout -b feature/#1
```
`git checkout -b`は以下2つのコマンドを実行するのと同じ結果となります。

```
git branch feature/#1
git checkout feature/#1
```

リモートリポジトリを派生元のブランチとして指定する場合
（ここではリモートリポジトリの`develop`ブランチを派生元とします）

```
git checkout -b feature/#1 origin/develop
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/c26cf63f-4e06-8c14-c964-4fb8ac90db7d.png)

以下コマンドによって現在のブランチ一覧（リモートリポジトリとローカルリポジトリのすべてのブランチ）を表示することができます。

```
git branch -a
```

### ローカルで変更した内容をステージング
ローカルでファイルの内容を変更した際、以下のコマンドによってファイルをステージング（commit対象として扱うこと）することができます。
ステージング対象が複数ある場合は、`ファイル名またはディレクトリ名`の箇所を半角空白区切りで複数分指定します。

```
git add ファイル名またはディレクトリ名
```
以下ディレクトリの場合、`test1-1.txt`・`text2-1.txt`・`test2-2.txt`の3ファイルが（内容に変更がある場合は）ステージングされる

```
sample1
　┗test1-1.txt
　┗test1-2.txt
sample2
　┗test2-1.txt
　┗test2-2.txt
```
```
git add sample1/test1-1.txt sample2
```
`git add .`によって変更のある全ファイルをステージングすることもできますが、意図しないファイルがステージングされ得るため、基本的にはファイル名やディレクトリ名を指定する方が良いです。

以下コマンドによって現在のステージングの状況を確認することもできます。

```
git status
```

### コミット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/c98d8fee-85f2-e1d1-84aa-dc6da20a9704.png)
ステージング中のファイルをコミットします。
コミットコマンドのオプションの指定方法によって、コミットログの書き方が変わります。
※ローカルリポジトリでコミットしただけでは、まだリモートリポジトリ側では変更が反映されません。

#### `vim`でコミットログを記述したい場合
```
git commit
```
vimが立ち上がりログを記述することができます。

#### `git commit`コマンドのオプションで、コミットログを記述したい場合
```
git commit -m "doHogeメソッドを削除"
```
コミットログは1行で表示されます。

#### `git commit`コマンドのオプションで、複数行でコミットログを記述したい場合
```
git commit -m "doHogeメソッドを削除" -m "doHogeメソッドを使用していないため"
```

以下コマンドによって現在使用しているブランチの過去のコミットの内容を見ることができます。

```
git log
```

### ローカルリポジトリの変更をリモートリポジトリに反映
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/2b520f9a-7f6a-b57b-0e27-aa6eb4225678.png)

```
git push origin feature/#1
```
リモートリポジトリに`feature/#1`ブランチが存在しない場合は、`feature/#1`ブランチが新規作成されます。
リモートリポジトリに`feature/#1`ブランチが存在する場合は、既存の`feature/#1`ブランチの状態が変更されます。

### リモートリポジトリの変更をローカルリポジトリに取込
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/b8a79b2d-b146-6357-9f07-192e740619cd.png)
「リモートリポジトリ上で、`feature/#1`ブランチから`develop`ブランチへのpull requestがマージされるなどにより`develop`の状態が変更した。そのリモートリポジトリの`develop`ブランチの状態をローカルリポジトリに反映したい。」などのケースで使用します。
（ローカルリポジトリでは`git checkout develop`により`develop`ブランチに移動しているとします）

```
git pull origin develop
```

`git pull origin develop`は以下2つのコマンドを実行するのと同じ結果となります。

```
git fetch origin develop
git merge origin/develop
```
`origin develop`はリモートリポジトリ、`origin/develop`はリモート追跡ブランチを指しています。
参考：[Git のブランチ機能 - リモートブランチ](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)

### ブランチの削除（機能開発の終了後に行う）

#### ローカルリポジトリの削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/1db554d7-5ed9-3cf2-681f-442e0a2bad30.png)
ローカルリポジトリの`feature/#1`を削除します。
自分が使用しているブランチが`feature/#1`である場合にはエラーとなるため、`git checkout`によって別ブランチに移動後に削除する必要があります。

```
git branch feature/#1 --delete
```
※リモートリポジトリの`feature/#1`はこの段階では削除されません。

#### リモートリポジトリで削除したブランチをローカルリポジトリに反映
リモートリポジトリ側で削除されたブランチも含めて、最新のリモートリポジトリの内容をリモート追跡ブランチに反映します。

```
git fetch --prune
```
`git branch -a`によって、ブランチが削除されたことを確認できます。

## 参考
[Git の基本](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-Git-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E5%8F%96%E5%BE%97)
[GitとSubversionの構造的な違い｜GitのブランチはSubversionのブランチとは全く違うモノ](https://www.ricksoft.jp/blog/archives/9483/)
[ガチで5分で分かる分散型バージョン管理システムGit](https://www.atmarkit.co.jp/ait/articles/1307/05/news028_3.html)
[リモートでの作業](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%81%A7%E3%81%AE%E4%BD%9C%E6%A5%AD)
[【初心者向け】git fetch、git merge、git pullの違いについて](https://qiita.com/wann/items/688bc17460a457104d7d)
[Git のブランチ機能 - リモートブランチ](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)