コンフリクトを起こさない開発フローを準備する
チームによる開発で一番頭を悩ませる問題は、ソースコードの「コンフリクト」(ソースコードの衝突・競合)です。コンフリクトとは、同じソースコードのファイルを、複数の開発者が同時に修正してしまうことで、どちらの修正を反映すべきか自明ではない状態になることを言います。例えば、図1のようにある開発者がAという機能を開発して、masterのソースコードを修正しているとき、別の開発者がBという機能を同時に開発していたとします。Aというバグを解消したmasterのソースコードが書き換えられた後に、機能Bだけを更新したソースコードでさらに修正してしまう場合があります。この時、Aの修正内容とBの機能とが、一つのソースコードの中で競合した状態になっています。これが、コンフリクトを起こしている状態です。
世界中のプログラマは、この問題を最小化するために、多くの方法を検討し、採用してきました。操作するソースコードのファイルは必ず一人が開発することを始めとして、更新中のファイルをロックして、他者に操作させない仕組みを搭載したり、ソースコードファイルを複数の開発者で更新してしまった場合に、それらをマージする仕組みを開発するなどしてきました。
Gitには「ブランチ」という機能があります。Gitリポジトリの中で、複数のブランチを準備することができます。これらのブランチは、相互に影響を及ぼさないため、ブランチごとに変更の履歴を管理することができます。ですから、機能を追加するブランチ、修正を行うブランチと、並行して開発を行うことができます。最終的に、masterと呼ばれるメインのブランチへマージしていくことで、各々の改修を反映するプロセスになっています。このブランチの仕組みを使って、Git FlowとGitHub Flowという2つの開発手法が編み出されました。これらの手法により、さらにコンフリクトを起こしにくいチーム開発が実現できるようになりました。
Git Flow
Git Flowは、バージョンごとのリリースアップデートを基本にした、これまでのアプリケーション開発に即したアプリケーション開発フローで、Gitのブランチを利用することで、より安全に並行開発を行うプロセスを提供します。
Git Flowでは、軸となる本番リリースを一つとして、複数の開発用ブランチを準備して、開発を進めていきます。必要なものは、図2のようにdevelop(そこから派生するfeature)、release、そしてhot-fixブランチです。
v1.0からv2.0へ段階的にリリースを行う想定では、開発の流れは次のようになります。
- v1.0のmasterブランチから、developブランチを準備
- developブランチ上で、次期リリースに向けた開発
- 必要に応じて、大規模な新機能などは、個別にfeatureブランチを準備して、そこで並行開発を行う
- もし本番リリースされているアプリケーションにバグが発見された場合は、現在稼働中のmasterブランチ(v1.0)からhot-fixブランチを派生させて、修正を行い、masterブランチへ統合(v1.1)
- developブランチでは、このhot-fixブランチでの改修内容をマージしながら、次期リリースへ向けてfeatureブランチもマージ
- 次期リリースに必要な機能が完成したら、releaseブランチへマージして、結合テストを行う
- 問題がなくなった段階でmasterブランチへ統合し、リリース(v2.0)
このように、Gitの肝ともいえるブランチ機能を利用して、複数のソースコードを並行開発し、マージを繰り返していきます。洗練された方法に見えますが、この方法にも欠点はあります。Git Flowを使った場合の問題点としては、「複雑である」ことが欠点といえます。ブランチを利用して自分の居場所を確認しながら開発できるこの方法ですが、常に複数のブランチを常設して制御・管理する必要があります。また、本番用のソースコードのバグを修正したhot-fixのコードをdevelop、releaseへと反映していく際に、コンフリクトの可能性もあります。この複雑性が、Git Flowで開発する場合の問題点です。
GitHub Flow
このGit Flowの問題点を解決すべく、先に紹介したプルリクエストを組み合わせた、新たな開発手法GitHub Flowが2011年に提唱されました。短期間でのデプロイ&リリースを繰り返すようなアジャイル開発に特化した、常に最新のソフトウェアを提供する開発手法です。大きなバージョンアップのために、複数の機能を同時にリリースするのではなく、図3のように小さな機能の修正を一つの単位として、ごくごく短い期間でソースコードの改修を行い、テストが成功したら、そのまま新しいソフトウェアをリリースする方法です。このように、ひとつひとつの修正単位を小さくすることで、同時並行で複数の開発が起こる要因を削減し、コンフリクトが引き起こされる可能性を最小化させることができます。
GitHub Flowを採用するには、次の2つの自動化が重要なポイントとなります。
- テストの自動化
- デプロイの自動化
具体的なGitHub Flowの流れをみながら、この2つの自動化の重要性について考えます。
- 機能の追加、修正、いずれにおいてもmasterブランチから、個別のブランチを作成
- ローカルのGitリポジトリ上に作成した、個別のfeatureやfixブランチにコミット
- GitHub上のGitリポジトリにも同名のブランチを準備して、定期的にローカルからGitHubへプッシュ
- プルリクエストを使って、他の開発者とやり取りを行う
- 作業完了の際にもプルリクエストを発行し、他の開発者のレビューが完了したら、masterブランチへマージ
- masterブランチへマージが完了したら、ただちにデプロイを実行
GitHub Flowでは、このように定期的にGitHubへのプッシュ操作や、プルリクエストでのやり取りを行います。また、他の開発者がソースコードのレビューを行うことも頻繁に発生します。この時、他の開発者がレビューを行うためにテストを行ったり、個別の開発環境へデプロイしてアプリケーションを確認したりする必要も出てきます。このようなデプロイ作業は1日に何度も行われることを想定しているので、テストもデプロイも、自動的に実行されなければ効率的ではありません。ですから、GitHub Flowを実現するためには、テスト・デプロイの自動化は必要不可欠なのです。
