Gitフローを見直して機能開発着手からリリースまでの流れを改善した話
はじめに
今年7月に中途入社した加藤です、ガムシャラにEASMの開発をしていたらいつのまにか年末になっていました、恐ろしや。
今回はEASMプロジェクト内でGitフローの改善を推し進めた話を紹介します。
現在弊社で開発しているEASMサービスのβ版についての詳細は以下をご参照ください。
https://www.securesky-tech.com/2023/10/26/6723/
※本記事における意見は、筆者の個人的な意見であり、所属団体や関与するプロジェクト等の意見を代表するものではありません。
今までのGitフロー
言わずもがなではありますが、私が入社する前からGitを用いて開発がされていました。しかし、自分が入社した時点では世に公開していない期間であったことや、開発者が少人数であったこともあり、自分が入社した後も暫くはシンプルな GitHubフロー を用いた開発を行っていました。
図としては上記の通りなのですが、具体的手順としては以下の様な手順となります。
main
ブランチのHEADからissue単位で開発ブランチをissue-100
やissue-110
の規則で切る- 開発ブランチ側で実装を進める
- ひととおり開発ができたら
main
ブランチにマージする main
ブランチの状態で 開発環境 へデプロイ- Terraformを用いたAWSの各種サービスのインスタンス類のデプロイ
- フロントエンド資材のデプロイ
とてもシンプルで分かりやすいGitフローだと思います。状況に応じてはこれで事足りるシチュエーションもあると思いますが main
ブランチは開発環境に相対する形としていたため、本番環境に相対するリリースブランチを作ってデプロイ作業を行う必要があります。
具体的に本番環境へのデプロイはどうするのかと言うと、前回のリリースブランチから新しいリリースブランチを作成して、リリース対象の開発資材(コミット)をチェリーピックして本番環境へデプロイしていました。
先程の図に本番環境へリリースするフローを付け加えると以下のような形になります。
例として issue-100
のリリースを先行して対応し、数日後に issue-110
の機能のリリースを行うとした場合のフローを描いてみます。
開発環境に相対している main
ブランチのHEADから作業ブランチを切るとなると、他の方の main
ブランチにはマージしているけど、作業途中で本番環境に反映してはいけないコミットが自分の作業ブランチに紛れてしまう可能性があるため、リリース対応者がリリースする対象のブランチのヒアリングを行い、コミットを1件ずつチェリーピックしてリリースブランチを作成するような対応を行っていました。
上記の図くらいのブランチとコミットの数であれば問題なさそうに見えますが、このフローだと開発リソースが増えたり、作業コミットが増えたりしてくると操作ミスによるチェリーピック漏れが発生したり、逆にチェリーピックしてはいけないものが release
ブランチに含まれてしまうなどの問題が発生してしまう懸念点が以前から挙がっていました。
それに加え release
ブランチを切る時点でもリリースしてはいけないコミットが含まれていないか、逆にデグレすることがないかを含めた目視でのチェックも必要で、こちらもヒューマンエラーの元になっていました。
上記の通りチェリーピック操作が必要となるため、対応できる人が限られてしまい、属人化が進んでしまっている状態も改善できたらと考えました。
変更後のGitフロー
EASMチームではスクラムフレームワークを用いた開発を行っており、Gitのブランチ戦略およびGitフローをよりスクラムのスプリント*1に沿ったフローに変更しました。
上記のフローがスクラム開発のスプリント15とした場合、開発着手からリリースまでの具体的手順としては以下の様な手順となります。
- 前回のスプリントの最後のコミット(
sprint-14
タグ)からPBI*2(pbi/***
)ブランチを作成する - PBIブランチから開発メンバーがタスクを細分化し、タスクごとのブランチ(
feature/***
)を作成し、実装を進める - ひととおり開発ができたらPBIブランチにマージする
- PBIブランチにマージされたのをトリガーとし、GitHub Actionsを用いてPBIブランチの内容を
main
ブランチに自動マージ - スプリントの締めに最後の
main
ブランチのコミットのHEADに対してsprint-15
タグを追加する - リリースの際はリリースブランチ(
release/***
)ブランチ前回のスプリントのタグから作成し、本番リリース対象のPBIブランチをマージしていき、デプロイを実施
スプリントごとにタグを打ち、そのタグを起点にブランチを切ることによって、スプリントにおける他のメンバーの開発途中のコミットが紛れることがなくなりました。
また、チェリーピック操作が一連のフローで基本的に不要となり*3、PBIの受け入れが完了したらそのままPBIブランチをリリースブランチにマージし、スプリント単位でリリース物を本番環境にリリースすることができるようになりました。
変更後のGitフローの問題点
では、これで万事解決かと問われたらそんなことはなく、変更後のGitフローにも多少なりとも問題を抱えています。
スプリント毎にタグを打つのは良いのですが、そのスプリントで開発が終わらなかったPBIが生まれてしまうと、次のスプリントのPBIブランチに開発途中のコミットが含まれてしまいます。
次のスプリントまでに持ち越ししたPBIの開発を終えることができれば、結果としてリリースブランチには本来リリースするべきものだけが集約されたブランチにできますが、途中まで開発したけどペンディング等の理由で main
ブランチにマージしたけど2スプリント以上跨ぐようなPBIが発生すると、リリースブランチに途中まで実装したコミットが紛れてしまいます。
その場合はリリースしたくない特定のコミットをrevertすれば良いだけなのですが、改めてリリースするとなった場合はrevertコミットのrevertを実施する必要があり、これもヒューマンエラーを発生してしまう要因になりえます。
また、開発ブランチが深くなったことで main
ブランチまでに必要なマージコミットが増えてしまうのと、最後の main
ブランチへのマージはGitHub Actionsで実施していますが、コンフリクトが発生しているのに気づかず開発環境にデプロイもされず時間だけ浪費してたなんてこともしばしば発生します。
終わりに
今回、スクラム開発に準拠するようなGitフローの変更を試みて、一定の効果を出すことに成功しました。
ただし、前述した問題点を解消するような、Gitフローを編み出せないかEASMの開発と並行しつつ検討している段階となります。
今回は完全にオリジナルなGitフローとなりましたが、次回はGit-flowやGitLab-flowなど、メジャーなGitフロー(もしくはそれを少しカスタマイズしたもの)をEASMのプロジェクトに適応できるかを検証するお試しGitリポジトリを作成して比較し、既存の問題点の解消と開発体験の向上ができないかを模索していけたらと考えています。
またGitフロー周りの更新を行い、改善することができた際は改めて投稿しようと思います。
*1:開発の計画と実装を行うための短く区切られた期間
*2:プロダクトバックログアイテムの略
*3:hotfix対応など突発的な対応が発生した場合は臨機応変にチェリーピックで対応することもあります