GitFlow + GitLab(GitHub)を活用した開発運用メモ

# 概要

私が参画しているとあるプロジェクトでは元々SVNでのソース管理をしていましたが、Gitでのソース管理(単純なSVNからGitへの移管)→GitFlowでの開発を導入して開発が効率化できたのでその要点・工夫等を共有します。
正式な手順と違う部分もありますが、参考になれば幸いです。

# 参画プロジェクトについて

参画プロジェクトは主に既存の自社パッケージ製品を保守・追加改修を行うようなプロジェクトです。(たまに新規顧客に対して導入を行うこともあります。)

PCローカル内のVM(VirtualBox等)もしくはDocker環境上で開発を行い、ソースをGitHub上で管理、最終的にはEC2やAzure Virtual Machines等のVM環境(CentOSやRed Hat Enterprise Linux)にRPMパッケージを転送後、展開することでリリース作業を行っています。

メンバー的にはプロパー社員 ＋ (人が足りていない場合)協力会社さんで開発を行っていますが基本的にパッケージ製品から大きな変更でない場合(少し機能を追加するだけ等)はプロパー社員だけの構成が多いです。

# 使用ツール等

## ソースコード管理サービス

- [GitHub](https://github.co.jp/)
- [GitLab](https://gitlab.com/)
- [Bitbusket](https://bitbucket.org/)

等のgitのソースコード管理サービス

※可能であれば、**ブランチの権限設定ができる**もので、**CI/CDの機能がある**ものが良いと思います。
上記3つはそれらを満たしています。

私の会社では[Backlog](https://backlog.com/ja/)の契約をしており、Gitの機能もついていましたが、ブランチの権限設定もCI/CDの機能も使えなかったため、GitLabで運用しています。
CI/CDの機能については別途JenkinsやCircleCI等のサービスを使用してもいいと思います。

ブランチの権限設定についてはGitの使用に不慣れなメンバーや操作ミスによるトラブルを防ぐために権限の設定機能があるものを選ぶのががいいと思います。

## 課題管理ツール

- [Backlog](https://backlog.com/ja/)
- GitHubやGitLabのIssues
- [RedMine](https://redmine.jp/)
- etc ...

ブランチの名前に使用したいので、可能であれば自動で連番を振ってくれるものがいいと思います。

## Gitクライアント

以下の内いずれかを使用

- VSCode
    - [gitflow](https://marketplace.visualstudio.com/items?itemName=vector-of-bool.gitflow)の拡張機能使用
    - gitflowの拡張機能をインストールすると`Ctrl + Shift + P`のコマンドパレットにgitflowのコマンドが表示されます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/a47d4c84-ee4e-f51d-7378-868ed60b3a0e.png)


- [SourceTree](https://www.sourcetreeapp.com/)
    - sourceTreeの場合GUIで操作することができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/83fa67d9-38e2-18e7-1403-c7dd5690d977.png)

- その他IDEやgitクライアント
    - (他におすすめのものがあれば教えてほしいです)
- (コマンドに自身があれば)gitコマンド

# GitFlow運用

GitFlow自体の説明は以下のページにおまかせするとして、実際に行っている運用を記載します。

https://nvie.com/posts/a-successful-git-branching-model/

https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow

※`master`ブランチについては最近のリポジトリでは`main`となっているので読み替えてください。

参考:

https://github.blog/changelog/2020-10-01-the-default-branch-for-newly-created-repositories-is-now-main/


## 運用

### まずはチケットを切る

開発課題、障害等ソースコードを触るのであれば、まずはチケットを切ります。
後述しますが、チケットの番号等でブランチを切り、そのブランチで何をしたのかを課題管理ツールで確認できるようにしておきます。

:::note
ソースコードを触らずに調査だけで終わってしまう内容であったり、データパッチやミドルウェアの更新等で済む内容であっても、情報共有のためチケットを切って詳細を記述しておくのがいいと思います。
(メンバーのためでもありますが、、未来の自分のためかもしれないのでとにかく情報を残すのは重要だと思います)
:::

### (開発時)チケットの番号でfeatureブランチを切って開発を行う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/19af3df3-bd67-7a9d-8804-6e4c2668c545.png)

Backlogの場合課題番号、GitLabやGitHubの場合はIssuesの番号でブランチを切ります。

```sh
### コマンドの場合のfeatureブランチの開始
$ git flow feature start PROJECTXX-1
```

GitLabやGitHubの場合、ただ単にIssuesの番号でfeature/1, feature/2 ...とするか、接頭辞をつけてfeature/Issues-1,feature/Issues-2...のようにするかは自由ですが、プロジェクトごとに統一しておく方がいいと思います。

(個人的にはIssuesと付いているとIssuesで管理しているんだなぁとわかりやすいような気がします。(ただの連番だともしかしたらとりあえず存在する番号+1で切っちゃう人も居るかも・・・？))
 
Backlogの場合は課題番号が{プロジェクトID - 連番}でつけてくれるのでそれを利用してfeature/XXPROJECT-1,feature/XXPROJECT-2...というようにつけていきます。

(↓Backlogの場合、Shift + クリップボードのマーククリックで課題番号だけコピーしてくれるので便利)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/552aeee9-85b3-4083-ff62-44a951cd2623.png)


:::note
コミットのログに最低限チケット番号(面倒でなければチケットタイトルも)を書くようにしておいて、後から「どういう経緯でこの変更を入れたのか？」がわかるようにしておくようにします。
:::

### マージリクエスト(プルリクエスト)を出す

featureブランチで開発が終わったらpushを行った後、
GitLabの場合マージリクエスト、GitHubの場合プルリクエストを出します。
宛先は基本的にPLを宛先として出すようにしています。

PLだけで捌ききれない場合や、PLが開発を行う場合には仕様理解度の高いメンバーを宛先にします。

マージリクエストのタイトルにもチケット番号＋タイトルを記載しておきます。

### コードのレビューを行ってマージリクエスト(プルリクエスト)の承認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/11a93c59-ef05-4387-c3d4-8bb8ba5f01d3.png)

マージリクエストを受けた人はコードレビューを行い、問題がなければdevelopブランチにマージします。

- 動作的に問題ないか
- コーディング規約的に問題は無いか
- コードフォーマットが行われているか
- わかりにくい表現は無いか
    - わかりにくくなってしまう場合、適切なコメントが書かれているか

等の観点でレビューをしていきます。


問題がありそうな場合、マージリクエスト内でのやり取りで指摘し、修正をしてもらいます。
軽微なもので、開発担当者がそのブランチを触っていない状況であればマージリクエストを受けた人が修正を行います。

:::note warn
開発担当者がバグに気づいて修正を行っている途中で勝手にコミットしてしまうと、競合が発生して面倒なことになるので確認は必須
:::

:::note warn
GitLab(GitHub)上でマージを行うので、ローカルのブランチは残ったままになります。
マージリクエストが承認されてdevelopへマージされたのを確認したらローカルのブランチは特に必要でなければ都度削除していきます。
:::


### リリースタイミングでreleaseブランチを切ってリリースを行い、完了したらマージする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/3494bb11-6656-b0cf-5933-2de9f4006895.png)

テスト等完了し、リリースを行える段階になったらReleaseブランチを切ります。

```
### コマンドの場合のreleaseブランチの開始コマンド
$ git flow release start 1.1.0
```

私の場合、releaseブランチ名は[セマンティックバージョニング](https://semver.org/lang/ja/)でいうところの{メジャー番号}.{マイナー番号}.0のブランチ名(release/1.1.0, release/1.2.0 ...)としています。

releaseブランチでは基本的にバージョン情報の書き換え等のリリース準備のコミットだけを行います。
(私のプロジェクトの場合RPMパッケージを作ってリリースしていたので、RPM作成時のバージョン番号の書き換えだけをコミットするような運用としていました。
※ただし、細かい文言の変更等の軽微な修正であればリリースブランチ内で行うこともあります。)

releaseブランチの完了時にmainブランチとdevelopブランチにマージを行い、タグを発行します。(git flowコマンドで各ブランチへのマージとタグの発行までしてくれます)

```
### コマンドの場合のreleaseブランチ完了コマンド
$ git flow release finish 1.1.0
```

:::note warn
releaseブランチからmainブランチ、developブランチにマージする際はマージリクエストは通さずローカルの`git flow`コマンド(SourceTree,VSCodeのgitflowコマンド)で行う運用としています。
developブランチで動作確認ができている前提としているためマージリクエストは不要という方針にしています。

問題があるときにはdevelopブランチからreleaseブランチへマージを行いますが、その際のマージリクエストの有無は特に決めていません。(featureからdevelopへマージされるときにマージリクエストが行われ2重になるため)
:::

:::note
後述しますが私達のプロジェクトの場合、releaseブランチにプッシュが行われたときにGitLab CI/CDを利用してビルドが実行されるようにしています。

このため、`git flow release finish`を行う前に一旦プッシュを行います。

ビルドが行われた後の生成物(リリース資材)がGitLabServerに保管されるようにしておいて、そのリリース資材でリリースを行い、実際にリリース作業を行ったあとで`git flow release finish`を行っています。
:::

### (障害発生時)チケットの番号でhotfixブランチを切って対応を行う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/80a0aa71-7b0e-7e47-64c5-ec1433f3c53e.png)

```
### コマンドの場合のhotfixブランチの開始コマンド
$ git flow hotfix start 1.1.1
```

ブランチ名は障害発生時までに切られているタグのパッチ番号を進めたものとします。
(タグ:1.1.0があるとき→hotfix/1.1.1ブランチを切る)

障害発生時で急いでいるときであってもチケットは切るようにします。
最低限どんな事象が発生しているか記載したチケットを切っておきます。
チケットの番号をコミット時のメッセージに書くようにします。

:::note warn
障害対応が終わったら、次に発生した場合や他のプロジェクトで発生したときにどのような対応をすればいいかわかるようになるべく詳細に記述します。
:::

:::note warn
releaseブランチと同じく、マージリクエストは通さずにmain、developブランチへマージします。
hotfixブランチが派生する＝急ぎで対応するという点と、障害発生時には複数人で確認を行いながら対応をしているので、マージリクエストは行わずマージして良いという方針にしています。
:::

:::note
releaseブランチと同じく、hotfixブランチにプッシュが行われたときにもGitLab CI/CDを利用してビルドが実行されるようにしており、hotfixブランチでコミットを行った後はプッシュを行いビルドが動くようにしています。

障害対応を行ったソースでリリース作業を行ったあとで問題がなければ`git flow hotfix finish`を行います。
:::

## CI/CD設定

上記のようなGitFlow運用をしつつ、releaseブランチとhotfixブランチにコミット(プッシュ)されたときにGitLab CI/CDを利用してビルドが行われるようにしています。

導入周りは以下の記事も参考にしていただければと思います。

https://qiita.com/g-iki/items/b8dbdc1384753efe6ada

.gitlab-ci.ymlサンプル

```yml
image: centos:centos7

build:
    tags:
      - docker-centos7-specific-runner
    script:
      - yum install -y rpm-build rpmdevtools # rpm作成に必要なものをインストール
      - sh create_rpm.sh # rpm作成のshell実行
    only: # ビルドが行われるブランチ指定
      - /^release.*$/i
      - /^hotfix.*$/i
    artifacts:
      paths:
        - RPMS/  # 生成されたRPMのパス
      expire_in: 5 days # 保管期限
```

処理の概要は以下のとおりです

- Docker上のCentOSでRPM作成に必要なパッケージをインストール
- RPM作成のShellを実行
- 生成されたRPMファイルの出力先ディレクトリをGitLabServer上に5日間保管
    - (5日間としているのはGitLabServerのファイル使用容量削減のためで、基本的にはReleaseブランチが切られてから数日中にはリリースが行われる想定)
- ビルドが行われるタイミングとしてreleaseブランチまたはhotfixブランチにプッシュが行われた時


:::note
masterブランチにマージが行われる際にリリースまでできると楽でしたが、顧客側の制約等で実現できていません。
GitLab CI/CDの導入により、リリース資材はGitLabServer側に保管された状態となるため、それを手作業でリリースするような運用としています。
:::

## 設定

### ブランチの保護

間違ってプッシュしてしまうことを防ぐためにブランチの保護を入れておきます。

GitLabを例に説明します。

GitLabの場合、設定 > リポジトリ > Protected branches から設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/d425eba7-95f5-2916-01d6-d79ca7ea573a.png)

GitLabの場合、プロジェクトに参加しているユーザーに対して権限を振ることができ、その権限ごとにブランチに対する権限を設定することができます。
※GitLabの権限については[GitLabの権限のページ](https://gitlab-docs.creationline.com/ee/user/permissions.html#project-members-permissions)を参照


私達の場合、以下のような設定にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/a0faea03-3473-88fd-8b3a-3dcb112e07ec.png)

メンバーの割り振りとしては
- Developersは協力会社の方や、git操作に不慣れなメンバー
- MaintainersはPLや緊急対応を行う可能性のあるメンバー

という割り振りにしています。
小さなチームなので、実質的にはMaintainersにプロパー、Developersに協力会社の方を割り振って、協力会社の方に作っていただいたコードはプロパー社員で責任を持って管理するような運用にしています。


:::note warn
本来であれば、main(master)ブランチは直接プッシュは誰もできないようにして、権限のある人だけマージのみで更新ができるのが正しいと思いますが、前述の通り緊急対応のhotfixをローカルでマージできるような運用にしているため、緩めの制限にしています。
:::


# 終わりに

一応今のチーム内での運用は以上の通りで手戻り等少なく運用できるようになりましたが、まだまだ改善できる点もあるかと思います。
もし、ここはこうした方がいいと思う！のようなご意見等ありましたら共有いただければ幸いです。