開発に使う主なgitコマンドと使い道

# はじめに

共同開発をする機会がありましたので、その際に調べたものをまとめておきます。内容は目次に記載されている通りです。


# 開発用のリポジトリを用意する

手順は以下の通りです。

1. Githubでリポジトリを作成
2. 任意の開発用ディレクトリにクローン

Githubでリポジトリを作成後、具体的には

```
cd (任意のディレクトリ）
git clone https://github.com/(githubアカウント名)/(githubで作成したリポジトリ名).git
```
のようにします。

これは、Githubの該当のリポジトリの`Code`と書かれている緑色のボタンを押せば出てくるので、それをコピペするだけです。

![green_button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393870/0815c400-e3df-71e6-2ca4-3f932c867a06.png)

![git_clone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393870/edd92418-4766-e583-bfd3-e22811445ddb.png)


# 基本的な開発の流れ

基本として、以下のような流れで開発が進みます。

1. Githubのリポジトリで、自分が担当のissueを確認
2. そのissue用のブランチを切る
3. そのブランチ内で開発を進める
4. 編集したファイルを見直す
5. コミット&プッシュ
6. プルリクエストを送る

具体的には、次のようなコマンドを使います。

```
git checkout -b <branch name>
git branch            #masterブランチにいないことを確認
git status            #編集したファイルを確認
git diff              #編集部分の確認
git add .             #ここでは全ファイルをステージングしている
git commit -m "<任意のコメント>"
git push origin <branch name>
```
ここまでの工程を行うと、Githubの`Pull request`から`Compare & pull request`が行えるようになっていますので、そこからプルリクエストを送ります。

### issueの書き方
[これ](https://gist.github.com/BcRikko/6af0b248148c12d3ab90) なんかを参考にしてみるとよいと思います。また、`ISSUE_TEMPLATE.md`、`PULL_REQUEST_TEMPLATE.md`という名前で、そのリポジトリにそれぞれテンプレートを作っておくと、テンプレートの状態から書き始められるので便利です。

![templates.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393870/bad08a2d-3733-a45c-f9f1-7bfe98ccb7e3.png)

![issue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393870/f89ba074-3a8b-f35b-9f4d-36ece1c7ff0c.png)


### pull requestの書き方

- [チーム開発におけるプルリクの作法](https://qiita.com/ikuwow/items/fb52a54c086398eb5b92)
- [GitHub「完璧なプルリクの書き方を教えるぜ」](https://qiita.com/umanoda/items/93aec41213f8e3ce14c8)
- [僕がコードレビューの時に気をつけていること](https://note.com/su_k/n/nf23ab5c6dba2)

などが参考になると思います。

また、pull requestの`desicription`欄もしくは`commit`メッセージに以下のキーワードと`#issue番号`を記載すると、マージされたときに自動でissueが`close`されるので便利です。

| キーワード |  |  |
|:---|:---|:---|
| close  | closes  | closed  |
| fix  | fixes  | fixed  |
| resolve  | resolves  | resolved  |

これらを使って、`close #13`のように書いておきます。

`PULL_REQUEST_TEMPLATE.md`にあとは番号を記入するだけでいいようにしておくのも一つの手です。

![pull_request_template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393870/1e44a83d-088a-3ed7-1cbf-3116a2caeb7e.png)


### ブランチの命名規則

ブランチの名付け方の一例を紹介します。

`<作業の分類>/#<issue番号><作業内容>`のようにするやり方です。

まず、作業の分類ですが、

| 分類 | 役割 |
|:---|:---|
| feature | 新機能開発中に使う |
| hotfix  | 公開中のもののバグ修正用 |
| review  | レビュー用 |

のように分けます。例えば、`新しい機能`を作りたいとします。その上で、Githubのissueに記されているissue番号が`19`番かつその機能がログインの実装であった場合、

```
git branch feature/#19implement_login_func
```
のようにするとよいです。

<br>

※<strong>git-flow</strong>というワークフローが有名なので、それに従うのも一つのやり方だと思います。

参考

- [【図解】git-flow、GitHub Flowを開発現場で使い始めるためにこれだけは覚えておこう](https://www.atmarkit.co.jp/ait/articles/1708/01/news015.html)
- [Gitflow Workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)

### コミット規約

これも一つの例として捉えてください。[【Git】コミットに規約をつくる](https://qiita.com/Kenya/items/f72fba8fecc79d1b090c)という記事を参考にしています。

#### 前提
- `1 commit 1 対応`を意識する。

例えば、新しい機能とバグ修正を行った場合、それぞれを分けてコミットすると言うことです。pull requestの際にレビューしやすくなりますし、特定の状態に戻るとき、などに良い効果をもたらします。また、`git rebase -i`を使えば`squash(結合)`できて`commit log`も編集できるので、特段問題はなく良い方法だと思います。

#### 原則

 1行目：コミットの全体的説明(タイトル)
 2行目：空白行
 3行目：変更内容の詳細(何をなぜ)を記述する

<strong>1行目</strong>

Fix：修正
Add：新機能もしくはファイル
Change：仕様変更
Remove：機能削除もしくはファイル

などのように大まかな意味をもつ単語でcommitの題意を伝えます。例えば、ログイン機能を追加する場合、

```
[Add] auth.pyにLogin認証する関数を実装
```

のようにします。もし、チーム内でさらに細かく分類する場合、

|  |  |  |  |  |
|:---|:---|:---|:---|:---|
| fix  | make  | move  | rename  | revert  |
| add  | merge  | check  | convert  | avoid  |
| remove  | support  | change  | set  | replace  |
| test  | update  | allow  | clean  | improve  |

などの単語が使えそうです。

<strong>2行目</strong>

あえて空白を入れるのは、commitをきれいに見せるためだそうです。

<strong>3行目</strong>

ここにはある程度詳細な内容を書きます。しかし、pull requestの際にもコメントを入れるので、ログを見たときにわかる程度に、言い換えれば、頑張りすぎない程度に書くとよいです。

よって、まとめると、

```
git commit -m "全体的説明" -m "（空白）" -m "詳細"
```
のようになります。

# pull requestを送ったら

pull requestを送ったら、レビューされ、mergeされるか、修正依頼がくるか、棄却されます。そのため、待っていても仕方がないので、次のissueに取り掛かります。

1. ローカルのmasterブランチを最新にする
2. 次のissueに取り掛かる

という手順を踏みます。ローカルのmasterブランチを最新にするには、

```
git checkout master
git pull
```

をします。ここで、`git pull`は`git fetch + git merge origin/master`を意味しますが、`master`ブランチでは何もしていないはずなので、`conflict`が起こる心配はなく、`pull`で問題ありません。

ローカルのmasterブランチを最新にしたら、先ほどと同様にして新しいissueに取り掛かります。

# pull requestの修正が必要で、最優先事項だったら

pull requestがレビューされ、結果今すぐ修正するようにと言い渡されたとします。しかし、すでに新しいブランチで異なるissueに取り掛かっています。

このような場合、`git checkout <修正が必要なブランチ>`をすると、

```
error: Your local changes to the following files
 would be overwritten by checkout: hogefuga.py
Please commit your changes or stash them before you switch branches.
Aborting
```

のようなエラーが出ます。そのため、一時的に現在開発しているブランチの内容で`git commit`を行うか、`git stash`でコミットせずに変更を退避します。

今回は、`git commit`するほどキリが良くない状況を想定します。この場合、次のような手順を踏みます。

1. 現在いるブランチの変更を退避する
2. 修正が必要なブランチへ移動する
3. 修正して確認、プルリクエストを送る
4. 元いたブランチへ戻る
5. 退避した変更を戻して作業を再開する

よって、

```
git stash save "message"
git checkout <修正が必要なブランチ>

編集して修正を完了

git status
git diff
git add .
git commit -m "message"
git checkout <元いたブランチ>
git stash list              # 退避したものを確認

退避した変更の名前を見る（一つしか退避していない場合）

git stash pop stash@{0}     # 元に戻す
```

とすればよいです。

# pull requestがmergeされたら

無事にmergeされたら、もう該当のローカルのブランチは必要ないので、削除します。


削除するには、

```
git branch --delete <merged branch> 

# git branch -d <merged branch>でも同じ
```

とすればよいです。これは現在開発しているブランチからでも可能です。

同時に、リモートのブランチも必要がないので削除します。これは、Githubのpull requestにある`delete branch`を毎回押せばよいのですが、忘れてしまうことが多いので、そうした場合は`settings`から`Automatically delete head branches`にチェックを入れておくとよいです。そうすれば、mergeしたときに自動で削除されます。

リモートのブランチは`restore`を押せばすぐに戻せるので、問題は特にありません。

本来はこの時にissueの`close`も行うのですが、先に述べたように、pull requestのcommentに`fix #13`のように書いておけば、mergeされたときに自動で`close`されます。


# 開発用ブランチで作業中にmasterの最新コードを取り込む

前提となるクラスや関数の仕様が変更されて、それを取り込んだうえで実装する必要がある、という状況が想定されます。そのような場合には、

1. 変更を一時退避
2. ローカルのmasterで最新状態へ
3. 開発用ブランチへ戻る
4. 最新を取り込む
5. 変更を元に戻す

という手順を踏みます。具体的には、

```
git stash save "message"    # git checkout masterが出来ない場合

git checkout master
git pull origin master
git checkout <development branch>
git merge origin master

git stash pop stash@{0}     # git stash saveをした場合
```

のようにします。コンフリクトが発生した場合、

1. コンフリクトしたファイルは原則master側の更新内容を反映
2. コミットしてコンフリクトを解消
3. コンフリクトしたファイルに自分の更新内容を反映
4. 自分の更新内容をコミット

のようにして解消するのがよいと思います。（[参考](https://bake0937.hatenablog.com/entry/2017/11/07/081616)）

# おわりに

僭越ながら参考にした記事をまとめさせていただきました。間違いがありましたら、教えていただけると幸いです。

# 参考記事

- [GitHubで共同開発のためのチュートリアル](https://qiita.com/takeokunn/items/5bc499121a21f8c5b990)
- [git初学者の初めてのチーム開発で気をつける事の備忘録](https://qiita.com/shh-nkmr/items/fde133cbdfa5f0092be1)
- [【Git】基本コマンド](https://qiita.com/konweb/items/621722f67fdd8f86a017)
- [【GitHub超初心者入門】この前初めてGitHubを使い始めたエンジニア見習いが書くGitHubの使い方と実践～とりあえず一緒に動かしてみようぜ！～]
(https://qiita.com/nnahito/items/565f8755e70c51532459)
- [Gitでローカルブランチを削除する](https://qiita.com/hogeta_/items/33d2334c9b1919bd5120)
- [GitHubでPullRequestを使った開発フロー]
(https://qiita.com/NAKKA-K/items/072e28c3f3ad7178f3a4)
- [【初心者向け】git fetch、git merge、git pullの違いについて](https://qiita.com/wann/items/688bc17460a457104d7d)
- [【Git】コミットに規約をつくる](https://qiita.com/Kenya/items/f72fba8fecc79d1b090c)
- [【git stash】コミットはせずに変更を退避したいとき](https://qiita.com/chihiro/items/f373873d5c2dfbd03250)
- [開発用ブランチにMasterブランチの最新コードを取り込む](https://bake0937.hatenablog.com/entry/2017/11/07/081616)
- [【メモ】Issueの書き方.md](https://gist.github.com/BcRikko/6af0b248148c12d3ab90)
- [チーム開発におけるプルリクの作法](https://qiita.com/ikuwow/items/fb52a54c086398eb5b92)
- [GitHub「完璧なプルリクの書き方を教えるぜ」](https://qiita.com/umanoda/items/93aec41213f8e3ce14c8)
- [Git で不要になったローカルブランチ・リモートブランチを削除する方法](https://qiita.com/iorionda/items/c7e0aca399371068a9b8)
- [【 git commit 】コマンド――インデックスの内容をローカルリポジトリに記録／保管する](https://www.atmarkit.co.jp/ait/articles/2003/19/news018.html)