よく使うGitコマンドとGitHubフローの流れ

## はじめに
今回、よく使うGitコマンドをGitHubフローの流れに沿って記事を書くことにしました。

なお、本記事の作成にあたって
[Git： もう怖くないGit！チーム開発で必要なGitを完全マスター](https://www.udemy.com/share/101WYW3@Fd4FpDOsl1o72kzGpqyXpa6koB0kX3GIv3UFWHdc1sr3Hn5exOrmRg5Or-ci5AJdkA==/)
[GitHub実践入門](https://amzn.asia/d/bfhtNK9)
[GitHub-Docs ~GitHub flow~](https://docs.github.com/ja/get-started/quickstart/github-flow)
を参考にしています。

## この記事の読者対象

- Git基礎学習を終えた方
- GitHubでの開発の流れについて学びたい方
- GitHub flowとは何かを学びたい方


## GitHubフローとは


GitHubフローは、シンプルでわかりやすいブランチベースのワークフローです。
GitHubフローの目的は、**開発フローをシンプル**にし、**mainブランチを常にデプロイ可能な状態に保つ**ことです。これにより、開発者が効率的に働き、プロジェクトがスムーズに進行します。  

#### ワークフローの全体は以下のようになります。

1. mainブランチは常にデプロイできる状態とする

2. 新しい作業をするときはmainブランチから記述的な名前のブランチを作成する

3. 作成したローカルリポジトリのブランチにコミットする

4. 同じ名前のブランチをGitHubのリポジトリに作成し、定期的にpushする

5. 助けて欲しいときやフィードバックが欲しいときはPull Requestを作成し、Pull Requestでやりとりする

6. 他の開発者がレビューし、作業終了を確認したらmainブランチにmergeする

7. mainブランチへmergeしたら直ちにデプロイする

この流れに従ってGitHub Flowで開発を進めることで、効率的な開発が可能になります。

## 実際の開発の流れ

#### リポジトリの準備


リポジトリをローカルにクローンします。
```
git clone <repository-url>
```

```
Git Tree
* main
```

#### 新しいブランチの作成
GitHubのIssueに対応する作業ブランチを、mainブランチから作成します。
実際作業を行うブランチは、このfeatureブランチになります。
branch名: ``feature/改修の簡単な概要``
```
git checkout -b <new-branch-name>
```

```
featureブランチで作業
          o---o---o feature (*)
         /
o---o main
```

#### 変更したファイルの一覧を見る
```
git status
```

#### 差分の確認
変更した差分を確認します。
```
git diff // ステージングエリアと作業ツリーの差分を確認
git diff <ファイル名> // 指定したファイルの変更内容を表示
git diff <コミットハッシュ> // 指定したコミットと現在の作業ツリーの差分を確認
git diff HEAD // 最新のコミットと現在の作業ツリーの差分を確認
git diff main feature // 指定した2つのブランチ間の差分を確認
```


#### 変更をステージ
変更もしくは新しく作成したファイルをステージングエリアに追加します。
```
git add <file-name> // 特定のファイルをステージングエリアに追加する
git add . // 全ての変更されたファイルと新しいファイルをステージングエリアに追加する
```

#### 変更をコミット
ステージングエリアの変更をコミットします。
```
git commit -m "commit message"
```

##### issue番号を含める際の書き方の例
GitHubのissueを作業を行う場合、以下のようにコミットメッセージにissue番号を記載することで、そのコミットがどのissueに関連しているのかを明示的にすることができます。
```
git commit -m "Add new feature, fix bug #123" // #123はissue番号
git commit -m "Add new feature, fixes #123" // issue#23が自動的にクローズする
```

参考: [Pull RequestをIssueにリンクする](https://docs.github.com/ja/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)

#### コミットを取り消したい場合
```
git reset <file-name> // ファイルをステージングエリア（index）から取り消します。
git reset <コミットID> // コミットを取り消しステージングエリアに戻す
git reset <コミットID> --hard // コミットの履歴を削除(指定したコミット以降の履歴も削除)
```

#### コミットログの確認
コミットログを表示します。


``--oneline`` : このオプションは、各コミットを短い1行のメッセージで表示します。コミットのハッシュとコミットメッセージの先頭部分が表示されるので、コミット履歴の概要を素早く把握できます。

``--graph`` : このオプションは、リポジトリの分岐とマージをASCIIアートで表現したグラフを表示します。これにより、ブランチ間の関係やマージのタイミングが視覚的にわかりやすくなります。

```
git log // 履歴を表示
git log --graph // ブランチの構造も含めたログを表示できます
git log --oneline // 各コミットの短縮されたコミットハッシュとコミットメッセージが1行で表示されます。
```



#### 変更をプッシュ
カレントブランチをリモートにプッシュします。
```
git push origin HEAD
```

#### プルリクエストを送る
GitHubにpushした後は、他の開発者にチェックしてもらうためにGitHub上でプルリクエストを送ります。
プルリクエストを受けた人は、コードの内容を確認してからレビューを行います。
参照: [pull request の作成](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request)

#### 改修依頼があった場合
レビューしてもらって改修依頼があった場合はローカル環境で改修を加える。
再度commitして,``git rebase -i``コマンドで履歴を一直線にしてからリモートにpush
```
git add <file-name>
git commit
git rebase -i
git push -f origin HEAD
```
``git push -f origin HEAD``は、ローカルブランチの変更内容をリモートリポジトリに強制的にプッシュするコマンドです。-f オプションを付けることで、リモートリポジトリにある同名のブランチにある変更を無視し、ローカルリポジトリの内容で上書きします。 


#### GitHub上でマージ
GitHub上で「LGTM」を頂いたら、マージを実行して完了。
LGTMとは、「Looks good to me」の略語で、「良さそうです！！」みたいな感じで、OKの時によく使われる。
GitHubのapprove機能を使って、レビュワーのうち誰か一人がOK出すまでマージ不可にしている現場もある。


#### 次のタスクの準備
mainブランチを更新して次のタスクに備える
```
git checkout main
git pull origin main
```

#### 作業ブランチを一旦退避
別のブランチで別のタスクに対応しなければいけないケースには、ブランチを退避させる
```
git stash
```



#### チームでの開発イメージ
- 開発フローの中心となるブランチはmainブランチで、ここから実際の作業はfeatureブランチで行います。
- 作業が完了したら、プルリクエストを送信し、レビューを経てmainブランチにマージします。
- プルリクエストを自分のローカルリポジトリに取り込むためには、pullコマンドを使用します。
- mainブランチは本番と同じ環境で、いつでもリリースできる状態にしておく。

#### 実際の流れ
featureA, featureBのブランチを作成
![sequence](https://user-images.githubusercontent.com/83809409/235333386-adeaee42-e159-4961-b10b-b1be37ccaf7e.svg)

こんな感じになっていく
![sequence](https://user-images.githubusercontent.com/83809409/235333872-f6e4ef3f-a356-4cc9-8a72-ec1b67f7cabb.svg)



## プルリクエストが送られてきた際のローカルでの確認方法

プルリクエストが送られてきた際に、ローカルで変更をチェックする方法は次のように行います。

#### リモートリポジトリをローカルに同期する
まず、最新のリモートリポジトリをローカルに同期してください。ターミナルで以下のコマンドを実行します。

```
git fetch origin
```
ここで、``origin``はリモートリポジトリの名前です。``origin``以外の名前でリモートリポジトリを設定している場合は、その名前を使用してください。

#### プルリクエストのブランチをチェックアウトする
プルリクエストに関連するブランチをローカルでチェックアウトしてください。以下のコマンドを実行します。

```
git checkout -b <local-branch-name> origin/<remote-branch-name>
```

``<local-branch-name>``には、ローカルで作成するブランチ名を指定します。<remote-branch-name>には、プルリクエストに関連するリモートブランチ名を指定します。例えば、リモートブランチ名が``feature/new-feature``である場合、次のようにコマンドを実行します。

```
git checkout -b new-feature origin/feature/new-feature
```

#### プルリクエストの変更を確認する

ローカルでチェックアウトしたブランチに移動した後、変更内容を確認します。``git diff``コマンドを使って、``main``ブランチ（または他のベースブランチ）と比較することができます。
```
git diff main
```

問題がなければ、プルリクエストを承認しマージする。
何か問題がある場合は、プルリクエストにフィードバックを提供し、修正を依頼する。


## pullとfetchの違い

git pullとgit fetchは、リモートリポジトリからローカルリポジトリへの変更の取得に関連するコマンドですが、それぞれ異なる動作を行います。以下で、それぞれのコマンドの詳細と、いつどちらを使うべきかについて説明します。

#### pull
git pullは、リモートリポジトリから最新の変更を取得し、現在のローカルブランチに自動的にマージします。これは、git fetchとgit mergeの組み合わせとして考えることができます。

git pullを実行すると、リモートリポジトリの最新の変更がローカルブランチに適用されます。ただし、自動的にマージされるため、以下のような注意点があります。

- マージが競合する場合、解決が必要です。このプロセスは、コードが予期せず変更される場合があり、注意が必要です。
- リモートリポジトリの変更が未確認のままマージされるため、ローカルでの変更と予期しない組み合わせが発生する可能性があります。

#### fetch

``git fetch``は、リモートリポジトリから最新の変更を取得しますが、ローカルブランチには自動的にマージしません。代わりに、リモートリポジトリの変更がリモートブランチに格納され、手動でマージすることができます。

``git fetch``の後、``git merge``を使用してローカルブランチにリモートブランチの変更をマージすることができます。これにより、次のような利点があります。

- 変更を確認してからマージを行うことができるため、不要な変更や競合を事前に防ぐことができます。
- 複数のリモートブランチから変更を取得し、それらを1つのローカルブランチに統合することができます。


#### pullとfetch & mergeの比較

##### git pull
変更が予想される場合や、競合のリスクが低い場合に便利です。ただし、自動的にマージされるため、変更が未確認のまま適用されるリスクがあります。
##### git fetch & git merge
手動でマージを行うことができます。これにより、競合や不要な変更を事前に防ぐことができます。複数のリモートブランチの変更を取得し、それらを1つのローカルブランチに統合する場合にも有用です。



## checkoutとswitch

git switchとgit checkoutは、Gitでブランチを切り替えるためのコマンドですが、それぞれ異なる目的と機能を持っています。


#### git checkout
``git checkout``コマンドは、Gitリポジトリ内で現在アクティブなブランチを切り替えるために使用されます。また、過去のコミットやブランチ、タグなど、リポジトリ内の任意の状態に移行することもできます。ファイルの変更を取り消すためにも使用できます。

具体的には、以下のような用途があります。

- 別のブランチに移行する
- 過去のコミットに移行する
- 特定のファイルの以前のバージョンを復元する

開発者が特定のブランチで作業していて、依存関係のために別のブランチで作業したい場合、``git checkout``コマンドを使用して別のブランチに切り替えることができます。また、特定のファイルの以前のバージョンを復元する場合にも、``git checkout``コマンドを使用して過去の状態に移行し、ファイルを復元することができます。

ブランチを切り替える際には、次のように使用します。
```
git checkout <branch-name>
git checkout -b <new-branch-name> // 新しいブランチを作成して切り替える
```



#### git switch
``git switch``コマンドは、Gitリポジトリ内で現在アクティブなブランチを切り替えるために使用されます。また、新しいブランチを作成してそのブランチに切り替えることもできます。

``git switch``コマンドは、``git checkout``コマンドと同様の機能を持っていますが、ブランチ操作に特化しており、意図しないファイルの変更や削除が発生しにくいという利点があります。

``git switch``コマンドを使用すると、以下のような操作ができます。

別のブランチに移行する
新しいブランチを作成してそのブランチに切り替える
``git switch``コマンドの利点は、ブランチ操作に特化しているため、意図しないファイルの変更や削除が発生しにくいことです。具体的な使い方は以下の通りです。

```
git switch <branch-name>
git switch -c <new-branch-name> // 新しいブランチを作成して切り替える
```