Mercurialではじめる分散構成管理

第5回分散による「多段連携」 ~ 大規模開発への応用

企業においてフリーソフト/オープンソースソフトを導入しようとすると、以下のような意見に反対されることがあるのではないでしょうか?

大規模開発では使えないんでしょ?

そこで今回は、大規模開発における構成管理を効率よく運用するための、Mercurialのリポジトリ分散性を活かした、幾つかのアイディアについて説明したいと思います。

中央集約形式の問題

ある程度以上の規模の開発の場合、事前に(あるいは開発を進めながら)取り決めたI/Fを介して連携する複数の部位に全体を分割し、複数のチームがそれぞれの担当分を開発する、という進め方をするのが一般的です。

このような開発体制を採用した場合、単一サーバが全ての要求を受け付ける中央集約形式のCVSやSubversionでは、サーバの応答性能低下が懸念されます。

図1 フラットな構成
図1 フラットな構成

また、全ての開発者が同様にメイントランクにアクセスしていたのでは、他拠点の開発成果とのマージが頻発しますので、拠点ごとにブランチを作成するなどの必要性が出てきます。

しかし、各ブランチ毎のアクセスを制限する方法がありませんから、他拠点成果との混交やメイントランクへのコミットが、誤操作等によって発生する危険が残ります。

この問題はリリースにおける成果混交と同じで、単にメンバー全員の習熟度を一定水準以上に保つだけ(開発体制が大きくなると、保つだけでも思いのほか難しいものですが)では解決しません。

ここで、各拠点ごとのリポジトリと、成果集約用のリポジトリに分離したとします。

図2 情報損失のある多段構成
図2 情報損失のある多段構成

しかし、リポジトリ間で作業成果を行き来させた際には、履歴等の構成管理情報が失われてしまいます。

各拠点での履歴などは必要ない

という場合もあるでしょうが、参照しない(do not)ことと、参照できない(can not)ことは全くの別物です。

リポジトリの多段構成

ここでは、開発全体が分割され、拠点1~Nにより担当される状況を想定し、以下のような構成を採用するものとします。

図3 分散多段構成
図3 分散多段構成

それでは、この構成での運用方法を、順を追って見て行きましょう。

「上り」方向の伝播ワークフロー

各拠点内での開発は、拠点内のマスターリポジトリを、開発メンバー間での共有リポジトリとして使用することで進めます。

図4 拠点内での構成管理
図4 拠点内での構成管理

このアクセスは全て拠点内で閉じていますので、以下のような影響は受けません。

  • 外部とのネットワーク接続のトラブル
  • 他拠点での平行開発によるリポジトリへのアクセス
  • 他拠点の中途成果とのマージのオーバヘッド

各拠点ごとの成果は、開発にある程度の目処が付く都度、拠点GW(Gate-Way)リポジトリに"hg push"します。

図5 成果の集約
図5 成果の集約

拠点側で公開前チェックや体裁を整える作業が必要であれば、リリース作業専用のリポジトリを用意して、アクティブな開発と切り離すのも良いでしょう。

マージのワークフロー

ここまでの手順で、各拠点の作業成果は、それぞれの拠点GWリポジトリに反映されました。

開発全体の構成管理担当は、各拠点の拠点GWリポジトリに反映された成果に対して、例えば以下のような受け入れ試験を行うことになるでしょう。

  • コーディング規約が遵守されていること
  • コンパイル時に警告・エラーが無いこと
  • ユニットテストが完走すること

それぞれの拠点GWリポジトリに対して、 作業成果のチェックを行いつつ、 マージ作業を実施します。

図6 拠点成果のマージ
図6 拠点成果のマージ

各拠点GWリポジトリの(受け入れ可能な)全ての成果に対してマージが済んだなら、マージ成果を開発マスターリポジトリへと反映します。

図7 開発マスターへの登録
図7 開発マスターへの登録

「下り」方向の伝播ワークフロー

開発マスターリポジトリの更新を契機に、各拠点GWリポジトリに対してマージ済み成果を反映します。

図8 拠点GWへの伝播
図8 拠点GWへの伝播

各拠点の構成管理担当は、定期的に拠点GWリポジトリを確認するなり、開発全体の構成管理者のアナウンスに応じるなりして、拠点GWリポジトリに反映された成果を、拠点内マスターリポジトリへと取り込みます ⁠=必要に応じてマージを実施します⁠⁠。

図9 各拠点への伝播
図9 各拠点への伝播

以上で構成管理のワークフローが一巡したことになります。以後は、このワークフローをひたすら繰り返すだけです。

フックによるアクセス制限

これまで述べてきた運用方法でも、一定規模以上の開発の構成管理を運用可能ですが、更に運用を便利にするための機能として、Mercurialにはフック(hook)と呼ばれる機能拡張方法があります。

ここでは簡単な例を元に、Mercurialのフックの概要について説明します。

なお、フックの種類・実行契機・利用可能な情報といったフックの詳細に関しては、Bryan O'Sullivan氏による"Handling repository events with hooks"等を参照してください。

「作成者」情報の問題点

Mercurialでは、各チェンジセットに記録される「作成者」情報は、 設定ファイルの"[ui] username"設定か、"hg commit"の"-u"オプション指定で任意に設定することができます。

そのため、悪意の有無は別として、不適切な「作成者」情報を持つチェンジセットを作成してしまう可能性があります。

以下、この「作成者」情報チェックを題材に、フックの実装例を説明します。

"hg commit"時のチェック

例えば、拠点1における開発では、⁠作成者」情報が以下の形式であるものとします。

username@division1

まずは「作成者」形式の確認用シェルスクリプトを作成します。

コマンド1
% cat ~/hghook/check.author.sh
#!/bin/sh

countinvalid(){
    hg log --template '{author}\n' -r ${HG_NODE}: |
    grep -v '^[a-zA-Z0-9_-.]*@division1$' |
    wc -l
}

test `countinvalid` -eq 0
% 

"countinvalid"関数の実行結果として、"hg commit"対象となるチェンジセット("HG_NODE"環境変数値)「作成者」情報から、期待するパターンに合致しないものの数が出力されます。

つまり期待するパターンに合致しないものが0の場合にのみ、このスクリプトは終了コード0で正常終了します。

次に、このスクリプトを実行するための設定を設定ファイルに記述します。

設定ファイルの格納場所は、設定の有効範囲に応じて複数存在しますが、まずはリポジトリ配下の".hg/hgrc"ファイルに記述するのが妥当でしょう。

コマンド2
% cat .hg/hgrc
[hooks]
pretxncommit.author= sh ${HOME}/hghook/check.author.sh
% 

"pretxncommit"は、⁠"hg commit"のトランザクションが確定する直前に実行される」フックであることを意味しています。

以上で準備は完了です。不適切な「作成者」を指定して"hg commit"を実行してみましょう。

コマンド3
% hg commit -m 'commit message' -u invalid@invalid
transaction abort!
rollback completed
abort: pretxncommit.author hook exited with status 1
% 

実行例からもわかるように、"pretxncommit.author"に設定したスクリプトにより、不適切な「作成者」による"hg commit"が抑止されました。

拠点GWリポジトリへの応用

先の「作成者」情報のチェックは、各拠点で完璧に実施されるのが理想ですが、万全を期するなら拠点GWリポジトリへのpush時点でもチェックするのが望ましいでしょう。

しかしながら、拠点GWには各拠点からのssh経由のpush(⁠⁠上り」方向)以外にも、マージ後成果の反映(⁠⁠下り」方向)があります。

この「下り」方向の反映では、対応する拠点の成果以外も含まれていますから、単純に先述のフックを適用することはできません(マージ成果の取り込みが出来なくなってしまいます⁠⁠。

そこで、⁠下り」方向の成果反映は、ローカルマシン上でのpushないしpullで実施するものとすることで、⁠作成者」チェックを以下のように実現することができます。

コマンド4
% cat ~/hghook/check.remote.author.sh
#!/bin/sh

countinvalid(){
    hg log --template '{author}\n' -r ${HG_NODE}: |
    grep -v '^[a-zA-Z0-9_-.]*@division1$' |
    wc -l
}

test x"${HG_SOURCE}" != x"serve" ||
test `countinvalid` -eq 0
% 

"HG_SOURCE"環境変数は、リモートアクセス時に"serve"値が設定されますので、その時(=各拠点からのpush)だけは「作成者」を厳格にチェックします。

また、拠点GWリポジトリ上では直接"hg commit"が実行されるわけではないので、フック設定も"pretxnchangegroup"に対して行ないます。

コマンド5
% cat .hg/hgrc
[hooks]
pretxnchangegroup.author= sh ${HOME}/hghook/check.remote.author.sh
% 

不適切な「作成者」のチェンジセットを含む"hg push"は、以下のように拒否されます。

コマンド6
% hg push
pushing to ssh://proj@host/hgrepo/dev
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added xxx changesets with xxx changes to xxxx files
remote: transaction abort!
remote: rollback completed
remote: abort: pretxnchangegroup.author hook exited with status 1
abort: unexpected response: empty string
% 

しかし、同一ホスト上からの直接的な"hg push"や、hgrepo/dev上から他のリポジトリに対する"hg pull"は、フックの影響を受けませんので、マージ成果はこれらの方法で反映させることができます。

おすすめ記事

記事・ニュース一覧