まず、BacklogではASP版とパッケージ版の2つのエディションを提供しています。これに加えて、開発中の機能を組み込んだベータ版の環境を用意してヌーラボ社内で使用しています。そのため、メインブランチとしては以下の4つのブランチを使用しています。
developブランチは普段の開発を行うためのブランチです。またリリースも、このブランチから直接行っています。リリース時にはタグを追加して、どのコミットの時点でリリースしたかが、後から分かるようにしています。
betaブランチはJenkinsを使用してテスト用環境やヌーラボ社内で普段使う環境にデプロイできるようになっているブランチです。テスト環境で動作を確認したり、新機能などの「ドッグフーディング」を行う場合はdevelopブランチをbetaブランチにマージするか、直接betaブランチ上で変更を行います。
betaブランチで直接変更を行った場合は、後からdevelopにマージして取り込みます。
開発は基本的にフィーチャーブランチを作成して行い、ブランチ名にはBacklogの課題キー名を使用して課題とひも付けています。フィーチャーブランチのマージは「ブランチがあったことが分かりやすいように」という理由で「Non Fast-Forwardマージ」を行うようにしていました。
しかし、コミット数の少ないブランチも全てNon Fast-Forwardマージを行っていると、並行して進んでいるブランチが多くなったときに履歴のネットワーク図が見づらくなってしまうことが分かったため、現在は基本的に「Fast-Forwardマージ」を行うようにしています。
また、フィーチャーブランチを後からフィーチャートグルでの開発に切り替えた例もあります。現在開発を進めているサブタスク機能の場合では、影響範囲が大きいためサブタスク専用のブランチで開発を進めていました。
ある程度開発が進んだので、ヌーラボ社内で実際にサブタスク機能を使ってみることになりましたが、そのためにはメインブランチにマージする必要がありました。そこで、メインブランチ上ではサブタスク機能の開発と、その他の機能の開発とリリースを同時に進められるように、データベース上のフラグでサブタスク機能を無効にできるようにしてからマージしました。
package-masterブランチはパッケージ版の開発を行うためのブランチです。パッケージ版専用機能の開発など、ASP版には必要のない変更のみを行うので、masterブランチにはマージしません。パッケージ版とASP版の両方に必要な変更は、developブランチで行ってから、masterブランチを経由してpackage-masterブランチに取り込みます。
上で紹介した現在のブランチ運用にたどり着くまでには、いくつもの失敗や試行錯誤がありました(現在もより良い運用を求めて試行錯誤を続けておりますが)。その一例として、ASP版(master)の変更をパッケージ版(package-master)へ適用する方法での失敗について紹介します。
以前Subversionを使っていたころ、Subversionの「マージトラッキング」機能を使い、ASP版の変更点のうちパッケージ版に必要なもの(コミット)を確認しながらマージしていました。マージトラッキング機能のおかげで、「どこは適用済みで、どこは未適用なのか」は把握できており、安心してマージできました。
Gitに切り替え後、Subversionのマージトラッキング機能と同じつもりでGitの「cherry-pick」を使い適用を進めていたのですが、cherry-pickした場合、変更内容は同じでもコミット自体は別のものとなってしまうため、どの変更内容が適用済みなのか分からなってしまう状況となり、非常に不安で危険な状態に陥いってしまいました。
そこで、やや大掛かりにはなりましたが、パッケージ版ブランチpackage-masterはいったん捨ててしまい、あらためてmasterからブランチを作成しパッケージ版固有の変更を適用し直すところからやり直しました。
そして、cherry-pickは本当に特別な場合のみの利用に限定し、ブランチ間のgit mergeで変更内容を適用する方針に変更しました。
もしパッケージ版で不要な変更内容がある場合は、そのコミットのみgit revertするようにしています。また、ASP版(master)とパッケージ版(package-master)のソースコードの違いを極力小さくし、ビルドやフィーチャートグルによる機能のオン/オフを実現するよう努力しています。
SubversionのマージトラッキングとGitのcherry-pickは概念的には同じように見えても各バージョン管理システムでのブランチのそもそものコンセプトの違いがあり、間違った運用をしてしまいましたが、Gitのブランチについて理解が深まったり、ブランチの運用やビルド方法、ソースコードの構成など、改善する良い機会となりました。
多くのバージョン管理システムでは、コミットやプッシュなどのアクションが発生した時に特定の処理を実行させるフックと呼ばれる仕組みを備えています。
また、GitHubやBitbucket、Backlogなどのバージョン管理システムにホスティングしているWebサービスの場合は、あらかじめ登録したURLでプッシュが発生したことの通知を受け取れるような仕組みを提供しているところもあります。
このフックを活用すると、他システムと連携して、さまざまなことが可能です。
Gitのフックは「クライアントフック」「サーバサイドフック」の2種類のフックに分けられます。
クライアントフックでは、コミットメッセージの入力を求められる直前に実行される「pre-commitフック」や、コミットか完全に終了した後に実行される「post-commitフック」など、さまざまなタイミングで任意のスクリプトを実行できます。
pre-commitフックでは、スクリプトからの戻り値によってコミットを中断することもできます。そのためコーディングスタイルの検査などを行い、結果に応じてコミットを中断させることで適切でないコードのコミットを防ぐといったようなことが実現できます。
サーバサイドフックでは、プッシュを受け取った直後に実行される「pre-receiveフック」や、プッシュによる処理が終了した後に行われる「post-receiveフック」などがあります。
このフック利用して、プッシュのあったタイミングでITS/BTSのチケットの状態を変更する、チケットにコメントを追加する、「Jenkins」などのCIツールを利用して自動テストを実行するなどの処理ができます。
pre-receiveフックでは、pre-commitフックと同じくプッシュを中断できるので、適切でないコミットがプッシュされることを防いだり、アクセス権限のないファイルへのアクセスを拒否するといったことが実現できます。
今回は構成管理の肝となるバージョン管理とその運用について紹介しました。次回は「継続的な統合(Continuous Integration)」です。お楽しみに。
Copyright © ITmedia, Inc. All Rights Reserved.