Git ブランチの運用

Git ブランチの運用ルールについて。主に納品がある受託開発に向けて考えた運用フローです。OSSや自社サービスには無駄なルールがあるかも。

## 概要

ブランチの役割は以下の通りです。

|ブランチ|役割|
|-----------|---------|
|`master`|本番サーバ(prod)用ブランチ|
|`dev`|開発検証サーバ(dev)用ブランチ。<br>`force push`可。|
|`stage`|ステージングサーバ(stage)用ブランチ。<br>`force push`可。|
|`feature`|機能追加、`milestone`中の作業用ブランチ|
|`milestone`|中長期マイルストーンブランチ。複数の `feature` をまとめてデプロイする。|
|`hotfix`|本番リリース済みの不具合対応。すぐにリリースする。<br>（`feature`で代用できるので無くてもいいかもしれない）|

**最重要事項**

- `master` 以外から派生させない
- `feature` は `master` に取り込まれるまで削除しない
- `milestone` に `push` しない

![Gitブランチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126845/fd2993bf-8f91-2266-e326-501204ac03ea.png)

## ルール

### `master`

- 本番サーバにデプロイする直前にマージする
- 全ての `feature` `milestone` `hotfix` の派生元
- できれば Pull Request を使う

#### 禁止

- `force push`
- `rebase`

#### 禁止じゃないけど気を付けて

- `push`
- 直接コミット

----

### `dev` `stage`

- 誰でも自由に `merge` `push` `force push` 可
- デプロイするためだけに使うので壊れてもOK

#### 禁止

- 絶対にここからブランチを作成しない
  - `force push` 可にしてるのでコミット消えます

#### 禁止じゃないけど気を付けて

- `rebase`

----

### `feature`

機能追加用のブランチ。`master` から派生させる。`milestone` にマージする前に最新の `master` をマージしておくとリリース直前での競合が少なくなります。

#### 禁止

- `master` にマージされる前にブランチを消す
  - `milestone` にマージしても絶対に消さないこと!

#### 禁止じゃないけど気を付けて

- `rebase`
- `force push`

`milestone` にマージした後にすると壊れます

- 派生元**以外**からのマージ

`master` から派生したら `master` だけをマージしましょう。他の `feature` をマージしたときは別々にリリースすることができなくなります。

----

### `milestone`

- 複数の `feature` ブランチをまとめてリリースする
- 競合を解消するときだけここからローカルブランチ派生させる
- **Pull Request のマージのみ可**


#### 禁止

- 直接コミット
- `push` `force push`
- `rebase`

このブランチを直接編集しないこと。`milestone` にマージした後にリリース対象機能を変更するときは `milestone` ブランチを破棄して再作成することになるのでコミットが消えます。

#### 競合の解消
`milestone` へのマージで競合が発生したときは全て `milestone` から派生させたローカルブランチで作業する。

**競合の可能性があるマージパターン**

```
master -> milestone

feature/1 ----+
              |-----> milestone    
feature/2 ----+
```


---- 

### `hotfix`

- 本番で不具合が見つかったときの修正用ブランチ
  - 名前は `hotfix` `feature` どちらでも可
  - `feature` で統一していいかもしれない

----


## 作業例

### 新しい機能を追加してすぐリリースする

1. `master` から `feature` ブランチを作成する
2. 機能を追加する
3. リリース前に `master` を `feature` にマージして競合を解消する
4. `master` に Pull Request を作成する

#### リリース前に動作検証する場合

3 の後に `stage` ブランチに `force push` してデプロイする。

----

### 機能1と2を追加して一緒にリリースする

#### 機能N

1. `master` から `feature/N` ブランチを作成する
2. 機能を追加する
3. `master` を `feature/N` にマージして競合を解消する
4. `milestone` に Pull Request を作成する

#### `milestone` リリース準備

1. `master` から `milestone/NAME` ブランチを作成する
2. Pull Request をマージする
3. `master` をマージする
  1. 競合がある場合はローカルで作業ブランチを `milestone/NAME` から作成する
  2. 作業ブランチに `master` をマージして競合を解消する
  3. `milestone/NAME` に Pull Request を作成する
  4. Pull Request をマージする
4. `stage` に `force push` して動作確認する
  1. バグが見つかったら `feature` ブランチを修正する (`milestone`から派生させない)
5. `master` に Pull Request を作成する

#### `master`
1. `milestone/NAME` の Pull Request をマージする
2. デプロイする

----

### マイルストーンの途中でリリースする機能を変更する

1. `feature` マージ済の `milestone/N1` を削除する
2. 新しい `milestone/N2` を作成する
3. リリース対象の `feature` の Pull Request を `milestone/N2` に作成する
4. 以降は通常の `milestone` リリースと同じ

#### 備考
リリース対象の機能が変わることはよくあるので `feature` を最後まで残す運用にしています。

また、リリース順序が変わると再度マージ作業が必要なため `milestone` をいつでも消せる状態にしています。そのため `milestone` からの派生は禁止しています。  
ただし `master` を `milestone` にマージしたときの競合解消だけは消えても問題ないので `milestone` から派生させています。（というよりリリース対象を変えたときはこの競合解消の操作も消さないといけない）

----

### ステージングサーバでバグを見つけた

1. `feature` を修正する
2. `milestone` に Pull Request を作成する

<div style="color: #f00">上にも書きましたが `milestone` からは派生させないこと</div>

----

### マイルストーンリリース準備中に別のバグ修正の検証をしたい

`milestone` をステージングで検証中に、緊急のバグ修正 `feature/bugfix` の検証をステージングでしたい。

1. `milestone` が `stage` にデプロイされている状態
1. `feature/bugfix` を `stage` に `force push` する
1. `stage` で動作検証して `master` にマージ
1. `milestone` を再度 `stage` に `force push` する

----

## 備考

### `force push` のやりかた
`push -f` ではなく `push --force-with-lease` を付けると壊れる前に警告がでます（一部のケースを除く）

```
$ git push --force-with-lease feature/bugfix:stage
```

- [git push -f をやめて --force-with-lease を使おう - Qiita](https://qiita.com/wMETAw/items/5f47dcc7cf57af8e449f)
- [git push `--force-with-lease`はいつも安全？ - Qiita](https://qiita.com/upinetree/items/5d0b224b8e53ad276ea0)