ツールなら簡単、でもプロセスは?

FishEye 開発チームは、アトラシアン内で DVCS へ切り替えた 最初のチームでした。アトラシアンには DVCS の経験者はいたものの、中規模の開発チームで仕事をするときに DVCS を使ったことがある人はほとんどいませんでした。私たちは参考になりそうな情報を Web で探しましたが、当時は、仕事で DVCS を使った経験を共有できるようにしている人はそれほどいませんでした。「 Git でブランチを push する方法」とか、「Mercurial で複数のリモートリポジトリから pull する方法」といった情報はたくさん見つかりました。しかし、「 15 人の開発者からなるチームが SVN から DVCS へ移行するための一番いいやり方」について説明した情報はほとんどなかったのです。

FishEye チームは、最初からいきなり DVCS のすべての機能を使うのではなく、 DVCS についてコツを掴むまで、今までの SVN のワークフローを踏襲することに決めました。結局、顧客に新しい機能をできるだけ早く提供する挑戦を続けていたわけですし、新しいワークフローを学ぶために開発ペースを落とすようなリスクは冒せなかったのです。

そこで、私たちはリリースの数週間前まで、 trunk で作業し続けました。その後は、リリースの直前までに取り込む機能とバグ修正を管理するため、リリースブランチを作成します。リリースブランチを作成すれば、すぐに次のリリースに向けた開発を trunk で始められるようになります。新しいバージョンがリリースできるようになると、あわれな開発者数人が、 SVN でリリースブランチを trunk にマージするという、時間も手間もかかるタスクに割り当てられていました。急いで取り込まないといけない修正は、ブランチ全体をマージするのではなく cherry-pick (修正を個別に取り出して適用する)することが当たり前になっていました。

実際には、私たちの開発チームは保守用に1つ以上のリリースブランチ(例えば 2.5 と 2.6 )を抱えることもありました。たまにあるバグ修正や重大なセキュリティ修正を同時に適用するためです。 SVN の場合、小さなバグ修正を管理するためには、これらのリリースブランチそれぞれに対して、同じ変更を 2、3 回適用するのが一番簡単だということも少なくなかったのです。これらのバグ修正は、最新バージョンにマージされなかったり、間違って適用されたり、時々はすでにリファクタリングされていたコードにマージされたりすることもありました。こういったあれこれが、バグ修正を適用するべき場所の把握を非常に難しくしていたのです。

SVN のワークフローを Mercurial のワークフローに移植するため、私たちは全てのコードをいったん default に入れました。これが Mercurial での trunk です。また、 Mercurial の提供するツールや概念に深く習熟するまでは、 histeditrebase といったコマンドを使って履歴を編集しないように開発者に強く言い聞かせました。

14人の開発者が活動しているチームでこのワークフローを回していくうえで、すぐわかる欠点は、 BitBucket でホストされているマスターリポジトリにいずれかのメンバーがコミットをプッシュした際、他の誰かが既に変更をプッシュしている可能性が高い、というものでした。そういった変更を統合するには hg pull; hg merge; hg commit をやらなければならなりません。それから hg push をして、他の誰かがあなたと同じ変更をすでにプッシュしていないことを願うしかないのです!古い SVN の習慣に従って、みんながコミットの たび に push しようとするようになりました。おかげで 大量 にマージする必要が生じました! Mercurial が 余計な仕事 を増やした!と息巻いている人も何人かいました。

フィーチャーブランチと継続的インテグレーション

幸いなことに、 DVCS は SVN に比べてブランチとマージがはるかに高速です。私たちはこの違いを default に対するマージですでに経験していたので、 DVCS の使い方について自信が深まるのにあわせて、私たちのワークフローにおける課題を解決するため、フィーチャーブランチについての検討を始めました。フィーチャーブランチという言葉に不慣れな方のために補足すると、フィーチャーブランチとは、開発者(たち)の取り組んでいる機能(フィーチャー)のコードが、その周りで行われる変更によって妨げられないようにするものです。フィーチャーブランチを使えば、開発者が自分たちのための R&D プラットフォームを持てるようになります。チームメイトのコードを壊してしまうことを気にせずに、フィーチャーを開発できるようになるのです。また、こうすれば、他の開発者が svn update をするたびに行っていたマージの量もイライラも軽減するのです。このブランチは、そのフィーチャーの開発、テスト、コードレビューなどを行っている間アクティブであり続けます。

フィーチャーブランチは私たちの開発手法にとってエレガントなソリューションになりました。しかし、 Bamboo のビルドでは大きな問題になりました。 default ブランチをビルドする際には、フィーチャーブランチと組み合わせたビルドは行われていませんでした。そのため、開発者たちはテストスイートをすべて手動で実行するか、フィーチャーブランチが default ブランチにマージされるまで待たなければならなかったのです。どちらの回避策でも、ビルドが再び成功するようになるのを待っている間は、開発者たちはコーディングの手を止めていたのです。

Bamboo のブランチビルド が登場するまでは、フィーチャーブランチをビルドするために default のビルドを複製していました。ですが Bamboo 4 になってこれが実に簡単になったのです。今では、フィーチャーブランチごとにブランチビルドができるようになりました。

あなたの使っている CI サーバーでブランチビルドができないなら、Bamboo 4 以前に私たちが行なっていたやり方が参考になるでしょう。私たちはメインビルドを複製して手動で実行するようにして、ソースコードリポジトリの設定にあるブランチ欄にビルド変数を指定できるようにしました。こうすると Bamboo のビルド計画を別々にしなくてもよくなるので、任意のブランチを好きなときにビルドできるようになります。(注: Mercurial ではコミットハッシュが同じように扱えます。なので、それはブランチの head でなくてもよいのです)今でも、ビルドを一回だけ行えばよいような小さなブランチではこのやり方を採っています。ビルドの結果は Crucible のレビューにリンクさせることができます。レビューアたちは、見ているコードを承認する前に、実際にビルドできていることを確認できるのです。

最後に、私たちはフィーチャーが完全になるまでコードを統合していませんでした。しかし、 Mercurial ではマージが容易であるため、この問題は対処が可能でした。チームはそれぞれ、 default にある最新の安定版とインテグレーションできるか確認したいときに、いつでもマージすればよいのです。

仕上げ期間

リリースまでの数週間は、私が好きなようにやりたいことをできる楽しい時間です。私たちは前述のテクニックを組み合わせて、できるだけ長い間リリースブランチがグリーンビルドを保てるようにしました。私はリリースマネージャとして、リリースブランチに対してコミットやマージを行うことを誰にも許しませんでした。すべての作業はフィーチャーブランチで行わなければなりませんでした。そして、 Crucible でレビューされ、 JIRA 課題がクローズされ、全てのビルドが成功したブランチだけしかマージしませんでした。各ブランチがこれらの基準を満たしているかどうかを追跡するため、私たちは FishEye リリースレポート を書きました。このレポートでは、リリースの間の全てのコードの変更を報告するだけでなく、そのフィーチャーブランチに対するコミットに関連した全ての JIRA 課題の状態も分かるようにしました。

リリースブランチへのマージの成功をより確実なものとするため、私はマージするもの全てに競合(自動解決されるものであっても)が起きないようにすることを義務付けました。 hg merge feature-branch と hg resolve –l (競合のあったものだけでなく、マージされた全てのファイルの一覧を出力するコマンド)が競合を報告したら、それがどのファイルレベルであっても、ブランチを開発者に差し戻します。開発者はもう一度私に提出する前に、自分でリリースブランチからマージを行い、 Bamboo に再び送信してグリーンビルドにしなければなりません。
開発者にとっては余計に時間がかかるように思うかもしれませんが、このプロセスによって、バグ修正に取り組む全ての開発者たちが、ビルドシステムの完全性に絶対的な信頼を持てるようになります。フィーチャーブランチにおける いかなる ビルドの失敗も、彼ら自身の変更したコードに起因することになります。彼らが開発を始める前は、リリースブランチのビルドは 常に グリーンだったからです。このようにビルドシステムが完全であるおかげで、チーム全体が多くの時間を節約できるようになりました。開発ワークフローから、調査の時間が大幅になくなったからです。

そのリリースの後も、私たちは進化し続けています。リリースブランチがグリーンビルドを保ち続けることで得られる成功を維持しつつ、独裁的なスタイルを幾分ゆるめて、もう少し柔軟なやり方を取り入れる挑戦をしているのです。そのためには、 FishEye リリースレポート とレビューのためのビルドが非常に重要です。

バグ修正のマージが簡単に

DVCS を使う上で私たちが見つけた別の問題は、以前のリリースに対するバグ修正と、後続のリリースにそれらのバグ修正を確実に取り込むようにすることでした。私たちの体験した最悪のシナリオでは、私たちは 2 つのリリースブランチと 1 つの開発ブランチを抱えていました(例えば 2.62.7 、そして default )。 2.6 に関する修正は全て 2.7 ブランチに含めなければなりませんし、 default ブランチにおいても同様でした。

DVCS でこれを行う最も簡単なやり方は、古いリリースに修正をバックポート しない で( SVN を使っていた頃はしょっちゅう起きていました)、修正の必要な 最も古い ブランチを修正するというものです。バグ修正のためのフィーチャーブランチをリリースブランチにコミットした人は、誰であれ、そのリリースブランチが開発ブランチだけでなく、将来作られる 全ての ブランチにマージされていることを確かめる責任を負うのです。このステップは 3 ~ 4 ヶ月前にリリースされたバージョンの間でバグ修正をマージする場合、とりわけ重要です。修正すべき箇所がリファクタリングされてしまって全く別のものになっているかもしれないからです。コードを書いた開発者以外に、それをマージすべきかどうかを誰が判断できるでしょうか。このプロセスは SVN のモデルよりもずっといいものです! SVN では、チェリーピックを行うか、そのバグを放っておいて、偶然見つけてしまった不幸な開発者に任せるか、どちらかでした。

しかし、以降のリリースには含めたくないリリースブランチに加えられた変更はどうすればよいでしょう?マージしなければ問題になるのではないでしょうか?私たちはこの問題を、前述したのと同じやり方で解決しました。リリースブランチを変更(例えば pom.xml のバージョン番号を上げるようなこと)したら、その人はそのリリースブランチに連なるあらゆる開発ブランチへそれをマージする責任を負うのです。マージをした開発者は、ファイルに対して実際行われた変更を元に戻してコミットし、それが戻ったことを確かめるという責任を負うのです。こうした方法をとることで、この変更を間違って下流にマージしてしまうということができなくなりました。 DVCS のコミットグラフに従えば、 その変更はもうマージされているのです!

一般的にこのポリシーは従いやすいものです。 Mercurial では、誰かが必ずやらなければならない仕事を、下流のリリースブランチにマージする場合、実際にマージをする前に、-Pオプションをつけてマージを行うことで確認ができます。 Mercurial はマージしようとしている実際のコミットを一覧表示してくれますので、他の人のコードをマージしようとしていないか確認ができるのです。もし、他の人のコードをマージしそうになっていたら、そのコードを書いた人をつかまえて、先にコードをマージするように要求すればよいのです。

あなたがリリースブランチを管理するためにこういったモデルを使わないとしても、 DVCS には別のやり方もあります。バグ修正やその他の変更を、2つ以上の全く別のブランチに対して行わなければいけない場合には、 共通の先祖ブランチの中で最古のブランチ からフィーチャーブランチを作成するのです。( Git にも Mercurial にも、共通の先祖ブランチの中で最古のブランチを特定するための 1 行コマンドがあります。)そうすれば、他の人のコミットを含めず、バグ修正を任意のあらゆるブランチに対して安全にマージできるのです。

DVCS しかない!

DVCS を使えば、間違いなく生産性が向上します。開発をより柔軟にできるようになることを別にしても、私たちはリリースブランチの品質を高く保ち続けられるようにワークフローを進化させることができたのです。DVCS はまた、開発者が大切な時に、周辺で起きていることによって気を散らされることがないようにしてくれる一方で、コードをインテグレーションする場合にはコントロールできるようにし、そのインテグレーションがうまくいくことを保証してくれるのです。最後に、リリースブランチ間でマージを行うことにより、個々のバグ修正が全て、それ以降の全てのリリースに統合されることが保証されます。

持ち帰って欲しいこと

  • フィーチャーブランチを使いましょう!
  • 自分のコードが最新の安定版のコードに統合できることを確認したければ、いつでも安定版のブランチをフィーチャーブランチへマージしましょう。
  • フィーチャーブランチを安定版ブランチへマージする前に、 CI サーバーを使ってフィーチャーブランチが正常であることを確かめましょう。
  • アクティブなブランチのどれが「下流」なのか明確なモデルを持ち、共通のバグ修正は、どんなときも最も上流のブランチに行うようにしましょう。

DVCS におけるその他のリソースについては、以下のリンク先をチェックしてください。

 

*本ブログは Atlassian Blogs の翻訳です。本文中の日時などは投稿当時のものですのでご了承ください。
*原文 : 2012 年 7  月 17 日 “Making the Switch to DVCS: The FishEye Teams move from Subversion to DVCS

(翻訳協力: グロースエクスパートナーズ株式会社)