小規模チーム開発のブランチ戦略を考える(GitHub Flowベース)
概要
筆者所属の小規模チームで採用したブランチ戦略について紹介します。
結論として、小規模チーム開発においてはGitHub Flowをベースに、必要な部分をアレンジしたブランチ戦略がマッチしやすいと考えます。
背景
筆者所属の小規模チームのスクラム開発において、ブランチ戦略が錯綜した時期がありました。
錯綜した結果として、管理している2つのブランチ間で齟齬が生じるようになり、ブランチ間の整合を合わせることに苦労しました。
そこで、シンプルで管理しやすく、仮にヒューマンエラーにより間違った運用をしてしまった場合も、リカバリしやすいブランチ戦略が求められました。
錯綜したブランチ戦略
開発当初は、git-flowをベースに少しアレンジしたブランチ戦略を採用していました。
ブランチ構成
ブランチ構成は次のとおりです。
- main
- 本番にデプロイするモジュールを作成するメインとなるブランチ
- hotfix
- 致命的なバグが発生した際に緊急で修正を加えるためのブランチ
- mainから作成し、mainとdevelopにマージする
- release
- リリース対象の変更がマージされたブランチ
- developから作成され、リリースのタイミングでmainにマージされる
- develop
- 開発環境にデプロイするモジュールを作成するブランチ
- 開発環境でのテストに使用し、テストをパスしたタイミングでreleaseにマージされる
- feature
- 機能開発を行うブランチ
- developから作成し、developへのマージ時点で削除する
この中で、永続的に管理をする必要があるのはmain
、develop
の2ブランチです。
また、本番にデプロイするのはmain
ですが、開発はdevelop
を主軸に進めていきます。
起こったこと
開発が始まった当初は、次の流れで開発を進めていました。
- 開発が終わった
feature
をdevelop
にマージ -
develop
を開発環境にデプロイし、テスト - テストが完了したら、
develop
からrelease
を作成し、リリースを待つ
しかし、開発を進める内に、スプリント内で開発がし切れず、リリースできない変更が出てきました。
実装、ソースレビューが終わり、develop
にマージしたものの、テストがし切れなかったり、テストで発生したバグの修正が間に合わなかったりなどの理由です。
develop
に乗った変更は何もしなければ最終的にmain
にマージされるため、テスト未完了の変更はdevelop
からrevertをすることで、リリースを回避、次のスプリントに回していました。
ただ、revertのし忘れにより未テストの変更がリリースされることを懸念し、develop
にマージしたfeature
のうち、テストをパスしたものだけを改めてrelease
にマージする運用に変更しました。
ここで、develop
とmain
の乖離が起きました。
テストをパスしたにも関わらず、release
にマージし忘れることで、main
に反映されない変更が出てきたのです。
develop
とmain
の乖離に気付かず、開発はどんどん進んでいきました。
途中、hotfix
が何度か挟まったこともあり、乖離に気付いた時には、develop
とmain
の間で競合が多く発生し、手作業での競合解決を余儀なくされました。
新たなブランチ戦略
元々のブランチ戦略でも、ルール通り運用ができれば、うまく回ったのだと思います。
ただ、スケジュールに追われる開発の中で、ブランチの管理にまで気を回すことができませんでした。
当初のブランチ戦略は自分たちのチームには手に余ると考え、機能開発が一段落したタイミングで、ブランチ戦略を変更することにしました。
変更後のブランチ戦略は、Github Flowを参考に、アレンジを加えたものにしました。
ブランチ構成
ブランチ構成は次のとおりです。
- main
- 本番にデプロイするモジュールを作成するメインとなるブランチ
- hotfix
- 致命的なバグが発生した際に緊急で修正を加えるためのブランチ
- mainと進行中のreleaseに変更をマージする
- release
- リリース対象の変更がマージされたブランチ
- mainから作成され、リリースのタイミングでmainにマージ、削除される
- 開発環境でのテストに使用する
- Github Flowの統合ブランチと似た用途だが、リリースごとに1つという特性がある
- feature
- 機能開発を行うブランチ
- releaseから派生し、releaseマージ時点で削除する
主な変更点は、なんといってもdevelopを無くしたことです。
永続的に管理するブランチをmain
のみにすることで、ブランチ間の整合を合わせる作業を最小限にしました。
release
は、スプリント開始時に作成、リリース時点で削除することにより、スプリントごとにリセットされるようにしました。これにより、仮にmain
とrelease
で齟齬が発生したとしても、影響を最小限に抑えることができます。
おわりに
今のところ、このブランチ戦略はうまく回っています。
ただ、状況により適切なブランチ戦略は変化していくものだと思っているので、今後も柔軟に見直し、うまく開発を回していきたいと思います!
皆さんのブランチ戦略検討の一助になれば嬉しいです!
Discussion