読者です 読者をやめる 読者になる 読者になる

あるプロジェクトのMercurial導入の軌跡

このエントリはMercurial Advent Calendar 2011 - PARTAKEの25日目です。

3月からMercurialを使い始めたので12月で9ヶ月目になります。一年の振り返りという事で、Mercurial導入の軌跡について簡単にまとめたいと思います。*1

Mercurialとの出会い

Mercurialと出会う前はSubversionとちょっとだけGitを触っていました。とくにSubversionは仕事でかなりがっつりブランチの運用*2を行っていました。

嫌になるほどSubversionを使うプロジェクトでは次の問題が発生していました。

  • Subversionでのブランチマネジメントはマージ担当者の負荷が高すぎる
  • リポジトリが巨大になりすぎてsvn stするだけでも20秒
  • リポジトリが巨大になりすぎてsvn upが終わらない
    • 部分svn upし出す人が増え、整合性に関するエラーにはまる人が続出
  • svn switchはまず失敗する
    • リリースターゲットを切り替えるにはチェックアウトが必須
  • でもsvn coするだけで1時間以上

Subversionをハードに使った人はたぶん同じ問題にぶち当たるのでは無いでしょうか。一つ一つの操作に時間がかかり、この遅さは次第に開発スピード、開発者のモチベーションにも影響してきます。

その結果、とにかくSubversionから移行するというだけの同意を得て、移行先となる分散バージョン管理システム(以下DVCS)の検討に入りました*3

結果、Meruciralが唯一移行できるDVCSだという事がわかり、本格的な移行が始まりました。

Mercurialの導入

Mercurialの導入には大きく三つの障壁がありました。一つ目はリポジトリの移行、二つ目はメンバーへのMeruciralの展開です。三つ目がデプロイツールの対応です。

リポジトリの移行

リポジトリ変換用の拡張ConvertExtension - Mercurialを利用する事によって、簡単にSubversionからMercurialへ変換する事が出来ました。

ConvertExtensionを使う上での注意点としては、履歴を保持したい場合は変換前にSubversionリポジトリのディレクトリ構成を変更しないという事です。ディレクトリ以下の履歴しか移行出来ないので、ディレクトリ構成を変更してしまうと、その履歴を失ってしまいます。

たいていの場合、直近の履歴だけ有れば事足りるので、移行時は思い切って捨ててしまうというのも手です。履歴を捨てるとリポジトリのサイズが小さくなると言う利点が有ります。

メンバーへのMeruciralの展開

Mercurialの使い方がわかる人間になる必要があると言うことで、自分の勉強がてら次のドキュメントを作成しました。

リポジトリをMercurailに切り替える前に、まず、全員にこのチュートリアル*4を実施して貰いました。あと、ほぼ全員に入門Mercurialを買って貰いました。

このチュートリアル以外に次の点に付いても講義形式で2、3回勉強会を開きました。

  • DVCSの概念
  • ブランチの概念の違い

今から同じ事を行う場合は次のドキュメントが利用出来ると思います。

これが最初のMercurial導入の為の準備でした。

デプロイツールの対応

このあたりの話はあまり詳しくありません。。すいません。。

Mercurialの運用

Mercurial導入後もブランチを切らずにSubversionの様な運用も出来ます*5。ですが、せっかくのMercurial、そのような運用をしてしまったら旨味が半減してしまいます。

ブランチ戦略

次のドキュメントを参考に、プロジェクトの運用にあわせたブランチ戦略をとりました。


本番のバージョンを1つしか持たないアプリケーションだったので、次の様な息の長いブランチを用意しました。「A successful Git branching model」のdevelopとreleaseが合体して、しかも複数有る運用だと思ってください。

default
リリースブランチ。このブランチの内容が本番にリリースされる。変更があった場合はdevelop/YYYYMMDDやhotfix/YYYYMMDDに変更内容をマージする
develop/YYYYMMDD
YYYYMMDDリリース用ブランチ。開発+テストを行う。リリースターゲットが複数有る場合は複数作成する。defaultから作成し、defaultにマージする。
hotfix/YYYYMMDD
YYYYMMDDメンテナンスリリース用ブランチ。基本バグ修正のみ。defaultから作成し、defaultにマージする。
ブランチ戦術

「bpmercurial-workflow ドキュメント」を参考に次のルールを定めました。

  • イシュートラッカーのイシュー番号毎にブランチを切る
  • コミットログにイシュー番号を含める

さらに、ブランチの命名規則は次の様に定めました。

  • 元の統合ブランチの名前をイシュー毎のブランチ名に含めること
    • 例: issue/XXXX-{簡単な説明}
    • 例: develop/YYYYMMDD/issue/XXXX-{簡単な説明}
    • 例: hotfix/YYYYMMDD/issue/XXXX-{簡単な説明}

このルールにより、イシュー毎のブランチがどこにマージできるかが明確になります。(YYYYMMDDが自分と同じか自分より大きいブランチにしかマージ出来ないです)

Mercurial拡張の位置づけについて

紹介したブランチ戦略、ブランチ戦術は、Mercurial拡張なしで運用出来ます。これはMercurialコマンドライン体系のセンスの良さが現れているのだと考えています。
より便利に運用するためにはMercurial拡張を使いこなす必要があります。バンドルされているMercurial拡張を使いこなすだけでも運用や、開発者一人一人の戦術が変わります。
運用後しばらく立ったら勉強会を開いて見るとよいと思います。実際に弊社では@yoppiblog によるMercurial拡張の説明会*6がありました。

rebaseは行うべき?

1日目23日目に書いたrebaseですが、このブランチの運用でrebaseすべきなのでしょうか?

僕の今のところの結論は「rebase出来る技量があるなら、なるべく行うべき」です。理由は次の通りです。

  • 履歴が一直線になるのでリビジョングラフが目で見てわかりやすい。*7
  • 履歴が一直線になるのでbackoutしやすい

なるべくとしている理由は次の通りです。

  • rebase方法によっては3-way mergeの恩恵にあずかれない可能性がある
  • いつまでもpush出来なくてrebase地獄の陥る可能性がある(merge地獄もあるけど。。)
  • rebsetsがあるので、履歴が路線図でもわかりやすいクエリで探せる

まあ、rebaseを使いこなすよりMQ*8使いましょう。より柔軟な運用が出来ますの。MQの性質上、履歴もまあまあきれいになります。

フォローアップ

DVCSを導入したからと言って、何でも問題が解決するわけではありません。適切に運用してこそ真価が発揮されます。運用が恥マテからは偉大な習慣が身に付くよう、事あるごとにVCSの使い方、思想を説明して行きました。

おさらい

長くSubversionを使っているからと言ってVCSを使いこなすための良い習慣が身についているわけではありません。導入を理由に次の事についておさらいしました。

  • コミット前にdiffを確認すること
  • コミットを論理単位で分割すること
    • 1コミットに1つだけの修正
    • ○○作業中というコミットをやめる
  • リビジョングラフの見方、ブランチの使い方
疑問を解決する

Mercurial基本的な使い方を学んで満足してしまうと成長がそこで止まってしまいます。慣れてきたメンバーには、こちらからそろそろ○○使ってくださいとお願いしたり、疑問点を教えてもらって一緒に解決するように努めました。具体的には次のような疑問がありました。

  • transplantの使い方
  • 変更の取り消し方
  • 逆方法マージについて
  • rebaseのユースケース
  • MQのユースケース
  • MQを使い始めると感じる疑問(ブランチを本当に切る必要があるのか)
  • push前のリビジョンの削除(hg strip)
  • パッチファイルの共有方法(hg export)

僕は神様じゃないのですべての疑問を解決することはできませんでした。その時はまだ僕の知識では解決できないということを伝え、自分でも調べてもらうようにお願いをしました。

Mercurial(DVCS)を導入して変化したこと

より高機能な道具を利用する事により、今まで当たり前のコストだと思っていた物が、低機能な道具を利用する事による弊害だという事に気づきました。

ブランチを効果的に利用出来るようになった

Subversionではなるべくマージを発生させないためのブランチ戦略をとります。この結果、リリースブランチを捨てる運用になりがちです。この考えの根底には「変更させないためにブランチを切る」という思想が有ります。

Mercurial移行後は考えが逆転して開発ブランチをリリースブランチに取り込む運用に変化しました。この考えの根底には「変更を行うためにブランチを切る」という思想があります。

Mercurialではサンドボックスとしてブランチが利用出来るため、他のメンバーに自分の作業途中の変更の影響が伝搬しません。Subversion時代は「○○作業中」というコミットログに泣かされましたが、Meruciralでは修正が完了した後統合ブランチに取り込まれるので事故が減りました。

一人の開発者に異なるリリースターゲットの作業をお願いできるようになった

「新規機能を鋭意開発中のメンバーに緊急の修正をお願いする」のはよくある話だと思います。
今まではsvn switchに時間がかかりすぎる為、緊急の修正でも即座に対応出来なかったり、svn switch失敗のリスクの大きさから、そもそもお願いする事が出来なかったりしました。
Mercurial移行後は、当たり前ですがブランチを安全に素早く切り替える事が出来るようになったため、このような悩みはほとんど無くなりました。また、開発者側も「とりあえず現在のブランチで作業した後、変更点をMQで目的のブランチに当てて確認する」といった柔軟な開発が行えるようになりました。

メンバーのVCSへの理解が深まった

Subversionを利用していてsvn mergeをしたことがある開発者はプロジェクトに何人居るのでしょうか?ブランチの使い方を理解していますか?

Mercurialでは空気のようにマージを行う必要があります。このため、必ず全員がマージの仕方を覚えます。Subversionでは限られた人しか使えなかったブランチですが、Mercurialでは簡単にブランチを作成出来るため、「変更を行うためにブランチを切る」という自然な考えでブランチを利用出来るようになりました。

今まで運用してきて感じたMercurialの強み

僕が特に強く感じている強みは次の通りです。普通の企業*9が選択するDVCSとしては最適だと思います。

  • コマンドライン体系が簡単なので、学習コストが低い
    • マルチプルヘッドが理解できればとりあえず使える
    • 自分の理解度に応じてMercurial拡張を選択できる
  • みんなに迷惑をかける操作がほとんど行えないので安全に運用できる

これから

当面の目標は「よくわかる人になって履歴改変してください!」です。
なるべく柔軟な運用が行えるように、メンバー全員に履歴改変スキルを持ってもらうことが目標です。履歴改変スキルがあれば影響の大きそうな機能はパッチベースでやり取りをして開発したり、backoutしやすいようにrebaseしたり、何でもできるようになります。*10

まとめ

Mercurial導入の軌跡を簡単に紹介しました。このエントリを参考にしてMercurialを導入して行く人たちが増えたらうれしいです。

本エントリで2011年のMercurialAdventCalendarは終わりです。今年から始まったアドベントカレンダーですが、参加者の皆さんのおかげでとても盛り上がりました。ありがとうございました。

*1:@gab_kmさんみたいに変態になりきれんかった

*2:subversionでのブランチマネジメント - TIM Labs

*3:svnからの切り替え先にbzrを検討するなど(最終的にはhgになった‥) - Togetterまとめ

*4:命名間違ったんだよねー

*5:MQ(MercurialQueue)を使うとブランチを切らない運用になりがちです。これはMercurialレベルが上がって、一周してしまったというやつです。見た目は同じですが、メンタルは全く別物です。

*6:内容はGit使いがMercurial使いに転職するとき設定しておくべきMercurial拡張 - TIM Labs

*7:キミはRabbitMQのリポジトリのリビジョングラフを見たことがあるか?!

*8:MercurialQueue

*9:とがってない企業

*10:なので、僕の担当するMercurialAdventCalendarでは履歴改変について力を入れました。社内のSkypeに「これ読んで使えるようになって!」とポストできるのでとっても楽です。