TIM Labs

subversionでのブランチマネジメント

| コメント(3) | トラックバック(0)

分散バージョン管理システムつかってますか?

世の中ではgitやhgなどの分散型のバージョン管理システムが流行していて、「もうsvnなんて、、、」「まだsvnつかっているの、、、」という風潮になっています。 弊社内でもgitのレポジトリが立ったり、svnのプロジェクトでも自分の環境だけはgit-svnで分散バージョン管理を使う人が増えています。

「自分の環境だけはgit-svnで」。そう、社内ではまだまだsvnを使っているプロジェクトが多いのです。「日本語のファイル名が使えない」「デザイナーさんに使ってもらうためのわかりやすいクライアントが無い」「svnからなかなか移行するコストが、、」などの理由でsvnを使い続けているプロジェクトも多いと思います。

というわけで、分散バーション管理システムではなく社内で運用されているsvnでのブランチマネジメントについて、備忘録もかねて説明します。

前提

次の様な前提で話をします。

  • trunk 開発、不安定版
  • testingブランチ 次期リリース用開発ブランチ
  • releaseブランチ リリース済み、メンテナンスブランチ

説明する構成はこちら。

  • trunk 一本
  • trunk + release ブランチ
  • trunk + testing + release ブランチ

trunk 一本

小規模なプロジェクトや、保守の少ないプロジェクトでよく見られます。 trunkで開発ないし保守を行い、リリース時にタグを打ちます。

              o (tags/release_2010_12_10)
              |
              |         o (tags/release_2010_12_13)
              |         |
              v         v
    o----o----o----o----o----o----o----o (trunk)

trunk + release ブランチ

  • リリース後にすぐに次の改修がスタートする。が、releaseしたアプリケーションもメンテナンスしなければならない

という状況で利用します。

            o (tags/release_2010_12_10)
            |
            |              o (tags/release_2010_12_13)
            |              |
            v              v
            o----o---------o (branches/release_2010_12_10)
           /
          /
    o----o----o----o----o (trunk)

releaseブランチのメンテナンス

ブランチマネージャというブランチを管理する役割をたてます。 releaseしたアプリケーションの修正はreleaseブランチに対して行います。 releaseの修正とtrunkで取りこぼさないために、ブランチマネージャはrelaseブランチに発生した修正をtestingにマージします。

    cd trunk
    svn merge -r A:C svn+ssh://hostname/path/to/svn/repos/branches/release_2010_12_10

            o (tags/release_2010_12_10)
            |
            |              o (tags/release_2010_12_13)
            |              |
            v              v
            A----B---------C (branches/release_2010_12_10)
           /                \
          /                  \ B-Cをマージ
    o----o----o----o----o-----o (trunk)

最近のsvnではmergeinfoというマージの情報が記録されます。マージ漏れを防ぐためにB-Cのように、常に-でつなぐ形になるようにしましょう。

    svn proplist -v .
    '.' の属性:
      svn:mergeinfo
        /branches/release_2010_12_10:B-C

マージバック

  • releaseへのコミットをコントロールしたい
  • svn switchのコストがあまりに高い場合

など、何らかの理由releaseで作業ができない場合はtrunkに修正を入れ、その修正をreleaseブランチにマージバックする場合もあります。 この場合、修正の数に比例して(releaseブランチの品質が低いほど)ブランチマネージャの負担が増加します。

trunk + testing + release ブランチ

  • releaseした後、開発と保守が続く。しかも、複数のマイルストーン設定されている という状況で利用します。 testingブランチには20101220がマイルストーンの機能のみコミットしていきます。 trunkにはそれ以降リリースの機能をコミットしていきます。

                 o (tags/release_2010_12_10)
                 |
                 |                  o (tags/release_2010_12_13)
                 |                  |
                 v                  v
                 o------------------o (branches/release_2010_12_10)
                /
               /
              /
             /         o--------o-------o----o-----------o--------o (branches/testing_2010_12_20)
            /         /
           /         /
          /         /
    o----o----o----o----o------------o-----------------o------------o (trunk)
    

この構成の場合のブランチのメンテナンスは二通りあります。

「release -> testing」、「testing -> trunk」を行う

「trunk + release ブランチ」の場合のメンテナンス方法をそのまま適応したパターンです。 releaseの修正はreleaseにコミット。testingの修正はtestingにコミットし、ブランチマネージャは 「release -> testing」のマージ、「testing -> trunk」のマージを順番に行う必要があります。

「testing -> relase」、「testing -> trunk」を行う

releaseの修正をtestingにコミットし、特定のリビジョンをブランチマネージャがreleaseにマージバックするパターンです。ブランチマネージャは「testing -> trunk」のマージだけを気にすればよく、順番に依存する事は無くなります。 マージの回数は増えますが、releaseには数コミットずつのマージしか発生しないため、衝突の解決が簡単になります。

testingのリリース

testingをリリースする場合は、testing20101220をrelease20101220にリネームします。 その瞬間前リリースブランチのrelease201012_10は役目を終え、メンテナンスを終了します。

    svn mv svn+ssh://hostname/path/to/svn/repos/branches/testing_2010_12_20 \
           svn+ssh://hostname/path/to/svn/repos/branches/release_2010_12_20

                 o (tags/release_2010_12_10)
                 |
                 |                  o (tags/release_2010_12_13)       o (tags/release_2010_12_20)
                 |                  |                                 |
                 v                  v                                 v
                 o------------------o (branches/release_2010_12_10)   o (branches/release_2010_12_20)
                /                                                    /
               /                                                    /
              /                                                    /
             /         o--------o-------o----o-----------o--------o (branches/testing_2010_12_20)
            /         /
           /         /
          /         /
    o----o----o----o----o------------o-----------------o------------o (trunk)

testingブランチの延命

期日までに開発が終わらなくなってしまった場合にtestingブランチを延命する事があります。

    svn cp svn+ssh://hostname/path/to/svn/repos/branches/testing_2010_12_20 \
           svn+ssh://hostname/path/to/svn/repos/branches/testing_2010_12_30
    svn mv svn+ssh://hostname/path/to/svn/repos/branches/testing_2010_12_20 \
           svn+ssh://hostname/path/to/svn/repos/branches/release_2010_12_20

                 o (tags/release_2010_12_10)
                 |
                 |                  o (tags/release_2010_12_13)       o (tags/release_2010_12_20)
                 |                  |                                 |
                 v                  v                                 v
                 o------------------o (branches/release_2010_12_10)   o (branches/release_2010_12_20)
                /                                                    /
               /                                                    /
              /                                                    /
             /         o--------o-------o----o-----------o--------o (branches/testing_2010_12_20)
            /         /                                            \
           /         /                                              o (branches/testing_2010_12_30)
          /         /
    o----o----o----o----o------------o-----------------o------------o (trunk)

その他のブランチ

個人用の作業ブランチ

「ある機能を実装するが、他の人のコミットに左右されたくない」という場合に利用します。 ある機能を入れたいブランチ(たとえばtrunk)から自分用のブランチを作成し、作業が完了したら分岐元のブランチにマージします。

    svn cp svn+ssh://hostname/path/to/svn/repos/trunk \
           svn+ssh://hostname/path/to/svn/repos/branches/troter/working \
           -m "troter用の作業ブランチ"
    # 作業ブランチにスイッチ
    svn sw svn+ssh://hostname/path/to/svn/repos/branches/troter/working
    # 何か作業してコミット
    emacs xxx; svn ci -m "hoge";
    # 分岐元にスイッチ
    svn sw svn+ssh://hostname/path/to/svn/repos/trunk
    # 作業ブランチでの変更をマージ
    svn merge -r n:m svn+ssh://hostname/path/to/svn/repos/branches/troter/working
    # コミット
    svn ci -m "○○を実装"
    # 用が済んだら消しましょう。
    svn rm svn+ssh://hostname/path/to/svn/repos/branches/troter/working

トピックブランチ

個人用の作業ブランチは人を主軸に置いた考えですが、人ではなく機能に主軸を置くとトピックブランチになります。ある機能を実装するためだけにブランチを作成します。 イシュートラッカー(trac、redmine)などのイシューの番号をブランチ名にするとわかりやすいです。

    svn cp svn+ssh://hostname/path/to/svn/repos/trunk \
           svn+ssh://hostname/path/to/svn/repos/branches/issue/2010 \
           -m "#2010 ○○機能の実装"

実装できたら個人用の作業ブランチと同じように分岐元に変更をマージします。

その他の話題

大規模な変更、リファクタリングを行うタイミング

ブランチマネージャの立場を考えると、trunk + releaseブランチしか存在しない瞬間に行ってほしいです。 それ以外のタイミングで行うとコンフリクトの解決が大変です。

testingからtrunkへのマージを行う間隔

testingとtrunkが乖離しないように頻繁にマージを行った方がよいです。 bugfixがメインの状態であれば40リビジョンくらいのマージでもそれほど苦労はありません。 開発がメインでどんどん変更される場合は15位を目安にマージした方がよいと思います。

ブランチの運用に困っている人に参考になれば幸いです。

トラックバック(0)

トラックバックURL: http://labs.timedia.co.jp/mt/mt-tb.cgi/92

コメント(3)

いやはや、苦労の跡が見られますね…

ところで、
・タグ名には日付を入れる
・ブランチ名には日付を入れ「ない」
のが個人的にはbetterだと思ってるんですけど、
やっぱりあると便利なんでしょうか。
本文だと日付をマイルストーンとして使ってるみたいですけど、
実際のところどうでしょう?

コミット時刻はログに残るわけですし、
「延命」でrenameする必要もなくなりますし、
何よりブランチ名を覚えられなくて困ることが多かったので、
某projectではブランチには日付入れるの辞めました。
# もちろん名前はsvn lsしりゃ出るでしょ、というのは確かですが。

名付けには困りますが、内部で使ってるalphaとかbetaとか、
いっそP1、P2、P3とかA、B、Cとかでも良いかな、とか…。

マイルストーンに明確な名前(フェーズNやマイページ機能改修など)があるのであればその名前を使った方がよいとは思います。その場合は提案通り、ブランチには機能の名前、タグにはブランチ名/日付を入れられて一番わかりやすい名前になりますし。

ただ、お客さんと共有しているマイルストーンが日付の事が多かったので、ここでは日付をブランチ名に採用しています。実際にメンバーとの会話でのM月N日リリースという話が多いです。「M月N日リリースがマイルストーンで、イシュートラッカーなどのマイルストーンも日付」のようになっていたら名前をつけたくても諦めて日付を採用した方がいいと考えています。

「全く異なる機能複数+バグフックス」の様な明確な名前をつけにくい状態の場合も、日付の方がわかりやすいです。
プロジェクトの状況に応じてわかりやすい名前を使えばよいのかなぁと。

指標としては「名前をつけた方がよいが、無理だったら日付」というのが現実的かなあと思います。かなり妥協していますが。。

なるほど。

「共有しているマイルストーンが日付、イシュートラッカーも日付」
という状況であれば、「マイルストーン名をブランチ名につけたら、
それがたまたま8桁の数字だった」というのが正しそうですね。

ウチの某プロジェクトの場合、
単にブランチ名が覚えられない(lsするのがめんどい)のが
主な原因で日付を入れるのを辞めたので、
逆にプロジェクト全体が日付をキーにして進んでいるのであれば
覚えられないなんて弊害はないでしょうし、
当然それが適切な名付けなんだろうと思います。

コメントする

このブログ記事について

このページは、troterが2010年12月 8日 11:21に書いたブログ記事です。

ひとつ前のブログ記事は「"site-packages に悩まされず"に buildout で GoogleAppEngine の環境を作る」です。

次のブログ記事は「ソースコードに色をつける」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。