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

第3回安全な「リリース」 ~ 複数リポジトリによる作業の隔離

今回は、不安定な成果物が混在するメイン開発ラインに対して、リリース作業の構成管理の独立性・平行性を、分散リポジトリを使って確保する方法について説明します。

「リリース」における成果混交の問題

「一度だけリリースしてしまえば、後は野となれ山となれ」という開発は皆無である、とは言いませんが、 一般的な開発の場合、以下のような契機での「リリース」が必要とされるのではないでしょうか。

  • 製品の出荷
  • 本リリース前の試用版の提供
  • 個別カスタマイズ版の提供
  • 障害修正版の提供
  • 開発期間途中での中間納品

こういった「リリース」の際、例えばCVSやSubversionといったモダンな構成管理ツールであれば、⁠タグ付け」「ブランチ」といった機能により、以下のようなことを実現します(体系的な詳細に関しては、パターンによるソフトウェア構成管理を参照されるのが良いでしょう⁠⁠。

  • ベースとなる版の決定
  • 固有の成果物の作成
  • 継続的な保守

しかし、中央集約リポジトリ形式の構成管理ツールの場合、⁠メイン開発」「リリース作業」のブランチが物理的に同一のリポジトリで運用されるため、不注意や誤操作、運用上の問題による両者間での予期せぬ成果の混交、といった問題には決定的な対応策がありません。

図1 成果の混交
図1 成果の混交

一方、分散されたリポジトリで構成管理可能なMercurialの場合、⁠メイン開発」「リリース作業」の2つの ⁠必要であればもっと多くの)用途向けに、物理的に異なるリポジトリを用意することで、両者間での作業成果の混交を容易に回避することができます。

共有リポジトリの立ち上げ

「メイン開発」「リリース作業」の2つにリポジトリを分離する前に、まずは「メイン開発」用の共有リポジトリを立ち上げましょう。

「メイン開発」用の共有リポジトリは、以下の方針で運用するものとして説明を進めます。

  1. リポジトリはメンバーで共有可能なUNIX系サーバ上で運用(以下"host")
  2. 開発用にプロジェクトアカウントを用意(以下"proj")
  3. "~proj"配下にリポジトリを作成(以下"~proj/hgrepo/dev")
  4. メンバーはsshでリポジトリにアクセス

共有サーバの用意や、projアカウントの作成などは、各自の環境におけるシステム管理担当に依頼してください。

リポジトリ~proj/hgrepo/devの作成は、第1回で紹介したように、"hg init"コマンドを使用します。

コマンド1
proj@host% mkdir -p ~/hgrepo/dev
proj@host% cd ~/hgrepo/dev
proj@host% hg init
proj@host% 

各メンバーのsshによるアクセスに関しては、以下のような設定にするのが一般的と思われます。

  • 専用グループを作成(以下"proj")
  • "proj"アカウントのプライマリグループは"proj"
  • "~proj"配下はグループ書き込み可能に
  • メンバーを"proj"グループに所属
  • メンバーは自身のアカウントでsshログイン

しかし、この方法には幾つかの問題点があります。

umask設定による書き込み権限のマスク:

「プロジェクト遂行以外の用途でのサーバアクセスは無い」と断言できる場合は別ですが、メンバーの個人設定はumaskが022、即ち「自分以外の書き込み禁止」以上の強度に設定するのが一般的です。

しかし、その設定で共有リポジトリに書き込みを行った場合、 別なメンバーは同じファイルに対して書き込みができなくなってしまいます。

NFS併用時のグループ所属上限:

NFSを併用する環境では、ユーザが16以上のグループに属する場合に、権限判定が適切に行われません。

これはNFSプロトコル仕様上の制約であるため、実行時に設定ファイル記述等で回避できる類のものではありません。

以上の理由から、筆者個人としては、⁠全メンバーがprojアカウントでsshログイン」する方法をお勧めします ⁠公開鍵によるアクセス制御等も容易ですし⁠⁠。

sshアクセスの準備が整ったなら、以下の要領でネットワーク経由での"hg clone"が可能です。

コマンド2
@client% hg clone ssh://proj@host/hgrepo/dev....
....
@client% 

自身のアカウント(以下"myaccount")でアクセスする場合、"hg clone"の引数に指定する対象リポジトリは、以下のように変更する必要があります。

コマンド 3
ssh://myaccount@host//home/proj/hgrepo/dev

上記例では"~proj"の絶対パスを"/home/proj"と仮定しています。 ホスト名の後ろの"//"は、パス指定が絶対パスであることを意味しています。

"hg clone"が失敗する場合、以下のコマンド実行により、問題が ssh 設定にあるのか Mercurial にあるのかを切り分けましょう(各自のアカウントでアクセスする場合は、"proj"部分を各自のアカウントに変更してください⁠⁠。

コマンド4
ssh proj@host hg help

実行結果により、"hg clone"の失敗原因がある程度絞り込めます。

"hg help"実行が成功:
リポジトリの位置指定が間違っているか、リポジトリ(あるいはそこに至るディレクトリ)のアクセス権限設定が不適切である可能性が考えられます。
"hg help"実行が失敗:

hgコマンドにPATHが通っていないか、 PYTHONPATH設定が不適切でMercurialのモジュールがロードできない可能性が考えられます。

対話的なログイン時と、非対話的なログインでは、読み込まれる設定ファイルが異なる場合がありますので、sshでenvコマンドを実行することで、環境変数設定を確認してみてください。

sshの実行そのものが失敗:
各自の環境のssh設定を見直してください。

以上で共有リポジトリの立ち上げは完了です。

"hg clone"に対するのと同じように対象リポジトリを指定することで、ネットワーク経由での"hg pull"や"hg push"も可能です。

「リリース作業」用リポジトリの分離

それではいよいよ「リリース作業」用のリポジトリを、⁠メイン開発」用のリポジトリから分離しましょう。

「リリース作業」用の共用リポジトリは、以下の方針で運用するものとして説明を進めます。

  1. 運用するサーバは「メイン開発」用と同じ("host")
  2. アカウントは「メイン開発」用と同じ("proj")
  3. "~proj"配下にリポジトリを作成(以下"~proj/hgrepo/release")
  4. メンバーはsshでリポジトリにアクセス
  5. ベースとする版のチェンジセットハッシュ値は"123456789abc"

1~4までは、「メイン開発」用の共有リポジトリ立ち上げの際と同じ手順で実施してください。

「リリース作業」リポジトリでは、特定の版を元に作業することになりますので、以下のようにして必要な成果を「メイン開発」リポジトリから取り込みます。

コマンド5
proj@host% cd ~/hgrepo/releasse
proj@host% hg pull -r 123456789abc ~/hgrepo/dev
....
proj@host% 

以上で、host上の"~proj/hgrepo/releasse"には、"123456789abc"を最新とする成果物が格納されました(厳密な話をするなら、単に"123456789abc"を指定した場合、⁠リリース作業」にとって不要なチェンジセットも含まれ得ますので、その場合はもう少し細かくチェンジセットを取り込む必要があります⁠⁠。

後は、リリース作業担当者に、"ssh://proj@host/hgrepo/release"から"hgclone"して作業するようにアナウンスすれば良いでしょう。

"~proj/hgrepo/release"リポジトリは、第1回でも説明したように、元となっている"~proj/hgrepo/dev"とは独立して機能しますから、意図的な操作をしない限り、⁠メイン開発」「リリース作業」間での成果の混交は回避されます。

図2 ⁠リリース作業」リポジトリの分離
図2 「リリース作業」リポジトリの分離

隔離度合いの強化

先の説明で例示した「リリース作業」リポジトリの運用方針は、⁠メイン開発」の運用方針のうち、リポジトリの格納されるパスを少々変更しただけの簡単なものです。

通常はこれでも十分だと思われますが、作業成果の隔離度合いを更に強化する場合、幾つかの方法が考えられます。

たとえば、⁠リリース作業」のベースとする版のチェンジセットハッシュ値(先の例では"123456789abc")をリポジトリの格納先ディレクトリ名に使用すれば、アナウンスを受けない限りはリポジトリ位置を特定できませんから、 明確な悪意を持ったアクセスでも無い限り、⁠メイン開発」から「リリース作業」への成果物の混入は、ほぼ皆無にできるのではないでしょうか。

コマンド6
proj@host% mkdir -p ~/hgrepo/123456789abc
proj@host% cd ~/hgrepo/123456789abc
proj@host% hg pull -r 123456789abc ~/hgrepo/dev
....
proj@host% 

他にも以下のような隔離方法が考えられます。

  • 「リリース作業」リポジトリ運用の専用アカウントを新設する
  • 「リリース作業」リポジトリを別のサーバで運用する

「リリース」後の成果の統合

「リリース」で全く何も変更が無い事もあるでしょうが、⁠リリース」が完了した際には、そこでの固有成果物の「メイン開発」への統合、即ちマージが必要になります。

とは言うものの、Mercurial で日常的に実施しているマージとさほど違いがあるわけではありません。

  1. 「リリース作業」リポジトリから最新の成果を"hg pull"
  2. 「メイン開発」リポジトリから最新成果を"hg pull"
  3. マージを実施
  4. マージ結果を「メイン開発」リポジトリに"hg push"

以上で終わりです。どうです、簡単でしょう?

図3 ⁠リリース」後のマージ
図3 「リリース」後のマージ

なお、マージ担当者が混乱しないためにも、⁠メイン開発」⁠リリース作業」の共有リポジトリのそれぞれを、常に枝分かれが無い状態に保つことは非常に重要です。

もっとも、枝分かれが発生してしまうような"hg push"を実施しようとすると、"-f"フラグを指定しない限り、 以下のような警告が表示されて処理が中断されますから、"pull"⇒"merge"⇒"commit"⇒"push"の手順さえ守っていれば、通常は枝分かれすることはありません。

コマンド7
% hg push xxxxxx
pushing to xxxxxx
searching for changes
abort: push creates new remote heads!
(did you forget to merge? use push -f to force)
% 

おすすめ記事

記事・ニュース一覧