彷徨えるフジワラ

年がら年中さまよってます

TortoiseHg の独自機能 〜 サブリポジトリの状態表示

このエントリは、Mercurial Advent Calendar 2013 の13日目です。

このエントリでは、前回の「TortoiseHg の独自機能 〜 変更の退避」に引き続き、TortoiseHg が独自に提供している機能として、「サブリポジトリの状態表示」について説明しようと思います。

サブリポジトリの詳細に関しては、別途私が公開しているエントリ等を参照してください。

作業領域中の状態表示

例えば、あるリポジトリ配下の subrepo にサブリポジトリがあるものとします。

サブリポジトリの作業領域中で、管理対象ファイル subrepo/file.txt に変更が加えられた場合、コマンドラインからの hg status による状態表示では:

$ hg status
$ hg status -S
M subrepo/file.txt
$

サブリポジトリ中の状態確認を明示的に要求する -S--subrepos)オプション指定が無い限り、サブリポジトの作業領域状態の確認は行われません。

その一方で、TortoiseHg のワークベンチ画面では:

サブリポジトリの作業領域中の状態に対して、以下の情報を得ることができます。

  1. 状態表示欄における、クリーンではない状態にあるサブリポジトリの表示
  2. 当該サブリポジトリ選択時における、サブリポジトリの内部状態表示

サブリポジトリの同期状況の表示

例えば、親リポジトリ側でのコミット時点において、サブリポジトリ subrepo の作業領域の親リビジョンがリビジョン番号 0 だったとしましょう。

もしも subrepo の作業領域が(subrepo における)リビジョン番号 0 以外のリビジョンで更新されているならば、Mercurial は親リポジトリとサブリポジトリの間で同期が取れていないものとみなします。

リポジトリ側でコミットされた内容は、サブリポジトリ subrepo のリビジョン番号 0 時点の内容に対して関連付けられたものです。そのため、subrepo の作業領域が参照しているリビジョンと異なる内容を持つ場合は、たとえ作業領域中に未コミット変更が無い場合でも、一種の「変更あり」状態と捉えるわけです。

サブリポジトリ subrepo の作業領域が、リポジトリで記録されたものとは異なるリビジョンで更新されている場合、コマンドラインからの hg status による状態表示は以下のようになります。

$ hg status
$ hg -R subrepo status
$ hg status -S
M subrepo/file.txt
$

-S オプション指定が無い場合(1つ目のコマンド実行)に何も表示しないのは、サブリポジトリの作業領域中に未コミット変更がある場合と同じですね。

subrepo 単独で hg status を実行した場合(2つ目のコマンド実行)、何も表示されませんから、「subrepo の作業領域中には未コミット変更は無い」ことがわかります。

それにも関わらず、-S オプションを指定した場合(3つ目のコマンド実行)は、subrepo/file.txt に対して「変更有り」(M)と表示されます。つまり、subrepo の作業領域中には未コミット変更が無いにも関わらず、親リポジトリからの状態表示では、「変更有り」とみなされているわけです。

このような表示は、慣れるまでは(慣れても?)奇妙に感じるかもしれません。

先述した実行例における subrepo 単独での hg status 実行を含む、一般的な hg status 実行で表示されるのは、作業領域の親リビジョンに対する状態表示です。

その一方で、親リポジトリにおける hg status -S における表示は、リポジトリ側で記録されたリビジョンに対する状態表示となります。

つまり、subrepo の作業領域の親リビジョンが、親リポジトリで記録されているリビジョンと異なる場合、作業領域中に未コミット変更が無くても、変更があるかのように表示されることになります。

hg status -S 出力における違和感の原因は、サブリポジトリにおける基準リビジョンが、通常の hg status と異なる点にあると言えます。

理屈としては明瞭ですが、あまりわかり易い表示とは言えないですね。

さて、その一方で TortoiseHg のワークベンチ画面では:

上記のように、親リポジトリ側で記録されたリビジョンと、現時点での作業領域の親リビジョンが異なっていることが一目瞭然です。コマンドラインでの出力と比較して、非常にわかり易いですね。

作業領域中の状態表示に関しては、常時 -S オプションを指定するようにすれば、コマンドラインからの実行でも同等の結果を得られますが、同期状況の表示に関しては、現状 TortoiseHg だけが表示可能な情報です。

ちなみに、先述した実行例での -R--repository)オプションは、処理対象となるリポジトリのルートを明示的に指定するものです。複数のリポジトリを連続して操作する場合、各リポジトリにいちいちディレクトリ移動する必要が無いので、覚えておくと何かと便利です(特に自動化スクリプト等での利用など)。

なお、-R オプションを指定した場合でも、引数で指定するパスはカレントディレクトリからの相対パスで指定しなければなりません。hg コマンド実行時に、カレントディレクトリ位置も移動させたい場合は、--cwd オプションを併用してください。

コマンドラインの仕様

さて、これまでは、「サブリポジトリ使用時は、TortoiseHg の表示の方がわかり易い!」旨を述べてきました。

しかし、コマンドラインの挙動が現状のようになっているのにも、それなりに理由があります。

-S オプション指定が無い限り、hg statushg diff などがサブリポジトリへのアクセスを行わないのは、ズバリ実行時の性能劣化を防止するためです。

英語版の Mercurial ユーザ ML では、数十単位のサブリポジトリを保持するリポジトリの運用例も度々報告されています。ひょっとしたら、それらのサブリポジトリの中には、数十万単位のファイルを管理対象にしているリポジトリがあるかもしれません。

また、Subversion 形式のサブリポジトリの場合などは、中央リポジトリへの問い合わせが生じるため、実行コストが非常に高価になります(同期している場合に限れば、キャッシュ情報を使って、ある程度安価に済ませられるのかな?> Subversion

そのような様々な状況を無視して、「常にサブリポジトリにアクセスする」挙動を一律有効にしてしまうと、利用者が本来必要としていない処理まで引き起こすことで、応答性能が一気に劣化してしまうかもしれないのです。

そのため、コマンドラインからの実行では、必要に応じて利用者が明示的に -S オプションを指定するようになっているわけです。

この辺は、一覧性やわかり易さ重視の TortoiseHg との、方向性の違いと言えます。

ちなみに、TortoiseHg を使いつつ、実行性能等の点からサブリポジトリの状態確認は省略したい、つまり -S オプション指定無しでのコマンドラインからの実行のような振る舞いにしたい場合は:

状態表示対象の選択の一環として、「サブリポ」ジトリを表示対象から除外してください。

なお、hg status におけるサブリポジトリの同期状況の表示に関しては:

--changed-subrepos オプション指定時に、サブリポジトリの同期状況を確認して、差異があれば S 表示するというのはどうだろう?

という提案が開発者MLに投函されたので:

--changed-subrepos よりは、.hgsubstate を想起させる --substate の方が良くねぇ?

返信して、「オーケー、それがいいね。他に意見は無い?」みたいな話になったのですが、その後何も動きがなく、放置された状態になっています……

折を見て私の方で修正パッチを投函しようかなぁ、と思いつつ、他のパッチ投函に手を取られて、未だに手付かず状態なんですよねぇ。「その機能は是非欲しい!」ツィート等あれば、私の中での優先順位も少しは上がるかも?(笑)