iOS開発におけるgit flow

iOS開発の際にgithub flowからgit flowへ移行したのでまとめておきます。

## git flowとは

git flowとは、Gitの機能であるブランチを活用したGitの開発手法でもあり、ツールの名前でもあります。

```
$ brew install git-flow
```

git flowは、役割ごとにブランチを使い分けます。

## 各ブランチの役割

### master

AppStoreで配布中の最新バージョンと同じです。
配布バージョンごとにタグを切ります。

### develop

開発ブランチです。
developブランチからIssue毎にfeatureブランチを作成し、開発を進めます。
次期バージョンの要件を満たしたらreleaseブランチを作成します。

### feature

developブランチからIssue毎に作成します。
対象Issueの開発が終わるとdevelopブランチにマージします。
developブランチにマージしたタイミングで対象のfeatureブランチは削除します。

### hotfix

AppStoreで配布中のバージョンで障害が発生した場合にmasterから作成する。 AppStoreでリリース申請通過後にリリース完了した時点でmasterとdevelopに(必要であればrelease featureにも)マージする。

### release

開発が完了したdevelopブランチから作成します。
Apple審査に出すリリースファイルはreleaseブランチから作成します。
審査を通過した場合、masterブランチにマージします。
審査を通過しなかった場合、releaseブランチ上で修正します。
releaseブランチ上で修正を行った場合はdevelop(必要であればfeature)ブランチにマージします。

## git flow コマンド

git-flowをサポートするためのGitの拡張コマンドがあります。

### git flow feaure コマンド

featureブランチでの作業開始時のコマンドは、次のようになります。

```
$ git flow feature start ブランチ名
```

featureブランチでの共有（push+track）時のコマンドは、次のようになります。

```
$ git flow feature publish ブランチ名
```



featureブランチでの作業終了時のコマンドは、次のようになります。

```
$ git flow feature finish ブランチ名
```

このコマンド1つで、featureブランチをdevelopブランチにマージして、featureブランチ自体を削除してくれます。

### git flow release コマンド

releaseブランチでの作業開始時のコマンドは、次のようになります。

```
$ git flow release start リリースバージョン
```

releaseブランチでの作業終了時のコマンドは、次のようになります。

```
$ git flow release finish リリースバージョン
```

この時に行われる作業は少し複雑です。
- releaseブランチをmasterブランチにマージする
- そのマージコミットにリリースバージョンのタグをつける
- releaseブランチをdevelopブランチにマージする
- 使い終わったreleaseブランチ自体を削除する
これら4つの作業を、コマンド1つで実行してくれます。


## その他コマンド

- [git-flow コマンド説明和訳](https://gist.github.com/Getaji/f5fa9b588bf1bfa6e21a)


## 作業開始からの流れ（サンプル）

以下チケットの「ユーザはFacebookから属性情報を取得することができる #2」タスクを行う。

### 0. 作業を始める前に

現在のブランチが`master`であるか確認する。（`*`が付いてる場所が現在のブランチ）

```
$ git branch

  develop
* master
```

リモートの`master`ブランチからファイルの更新を取得する。

```
$ git pull
```

外部ライブラリを更新する。

```
$ carthage update --platform iOS
$ pod update
```

### 1. featureブランチの作成

#### ブランチ作成

```
$ git flow feature start 2_login_with_facebook
```

※ ブランチ名は対応内容がわかる名前をつけること。
本サンプルの場合、既にIssueが作られていたため先頭にIssue番号をつけている。

#### コミット

作業による変更があった際はなるべく細かくコミットしておく。
そうすることで変更を戻したい場合に「余分に戻らなければいけない」などという現象を防ぐ。

コミットメッセージは日本語でも良いが先頭に必ず対応するIssue番号を付ける。

```
$ git add .
$ git commit -m 2_ログイン処理を追加
```

※ addコマンドは`.`を指定することですべてのファイルを対象とする。
commitコマンドは`-m`オプションを付けることでインラインでメッセージを追加できる。

#### リモートブランチへプッシュ

ローカルの変更内容をリモートブランチに登録する。

```
$ git flow feature publish 2_login_with_facebook
```

※ プッシュを行うのは全ての作業が終わったタイミングで大丈夫だが、日を跨ぐ際は念のためプッシュしておくと良い。


#### プルリクエストを送る

ブラウザもしくはhubコマンドを利用してプルリクエストを送る。

##### hubコマンドを使った例

現在いるブランチの状態をプルリクエストに変換できる。

```
$ hub pull-request -i 2 -b develop
```

`-i`オプションにIssue番号を付けることでそのIssueをプルリクエストに変換してくれる。
`-b`オプションでプルリクエスト先を設定する。

※ 既にIssueが存在するため、異なる番号のPull Requestを作ると相互リンクさせたりすることが手間なため hub コマンドを使用している。

#### レビューが通る

プルリクエストを送り、レビュアーから許可が下りたら**ローカル上**でマージをする。

finishコマンドでfeatureからdevelopへマージし、ローカルのfeatureブランチを削除する。
その後、pushしてリモートを最新化する。

```
$ git flow feature finish 2_login_with_facebook
$ git push --all
```

#### 別のfeatureをローカルに取り込む

別のfeatureをクローンする。
ローカルで動作確認やレビューを実施したい場合に使う。

```
$ git flow feature track FEATURE_NAME
```


### 2. releaseブランチの作成

リリースブランチを作成する。今回はバージョン1.0.0を例とする。

```
$ git flow release start v1.0.0
```

リリースブランチに修正がある場合はプルリクを作成する。

```
$ git flow release publish v1.0.0
```

リリースブランチの終了とともに、masterにマージされる。
デフォルトだと`v1.0.0`がタグ名となる。

```
$ git flow release finish v1.0.0
```

ブランチがmasterに切り替わるのでpushし、masterを最新化する。

```
$ git push --all
```

タグをリモートにpushする。

```
$ git push origin --tags
```

### hotfixブランチの作成

バグ等で緊急リリースが必要な場合は、hotfixブランチを作成する。
VERSIONにはホットフィックスのリリース名を指定。リビジョンを1つ上げる。

```
$ git flow hotfix start v1.0.1
```

対応が完了したらホットフィックスを終了する。

```
$ git flow hotfix finish v1.0.1
```

※ ホットフィックスの対応をするにあたり、リリースタグの一覧はこのコマンドで確認できる。

```
$ git tag
```

## 参考
- http://jumperson.hatenablog.com/entry/2015/06/30/070343
- http://liginc.co.jp/248864