彷徨えるフジワラ

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

series ファイルを直接編集せずにパッチ適用を制御

TokyoMercurial #1 で話題になった件の詳細シリーズ - その3。

MQ で管理しているパッチが複数ある場合、適用順序を入れ替えたり、適用の要否を制御したくなったりすることが多々ある。

純粋に適用順序を入れ替えたい場合、僕なら脊椎反射的に .hg/patches/series ファイルを編集しちゃうのだけれど、これが皆に薦められる手法か?と言うと、流石にちょっと不恰好で美しくない。

1つ2つ程度の順序入れ替えであれば:

$ hg qseries
1st
2nd
3rd
4th
$ hg qapplied
$ hg qpush --move 3rd
applying 3rd
now at: 3rd
$ hg qseries
3rd
1st
2nd
4th
$ hg qapplied
3rd
$

上記のような "hg qpush" への "--move" オプション指定によって、パッチ適用順序を変更してやれば良い。

一時的にパッチの適用を抑止したい場合は、パッチ順序の入れ替えではなく、qguard/qselect を使用するのが便利。
例えば、先の例のように 1st 〜 4th のパッチが MQ 管理下にあって、何らかの理由により一時的にパッチ 2nd の適用だけを除外したい場合、適用順序を入れ替えて 2nd を末尾に移動させた上で、適用対象から除外しても良いのだけれど、『うっかり戻すのを忘れた』とかで痛い目に会うのが目に見えている。少なくとも僕は、あまり自分を信用していないので (^ ^;;)。

で、こういった場合は、"hg qguard" を使用することでパッチ 2nd の適用を抑止してやれば良い:

$ hg qapplied
$ hg qguard 2nd +drop_temporarily
$ hg qpush -a
applying 1st
skipping 2nd - guarded by '+drop_temporarily'
applying 3rd
applying 4th
now at: 4th
$ hg qapplied
1st
3rd
4th
$

実行例のように、"hg qpush -a" により『全パッチ適用』を指示しても、『ガード』指定の付いたパッチ 2nd の適用は抑止される。

2nd を適用したい場合は、2nd に設定した『ガード』を、"hg qselect" によって選択してやれば良い:

$ hg qapplied
$ hg qselect drop_temporarily
number of unguarded, unapplied patches has changed from 3 to 4
$ hg qpush -a
applying 1st
applying 2nd
applying 3rd
applying 4th
now at: 4th
$ hg qapplied
1st
2nd
3rd
4th
$

# "hg qselect" への指定では drop_temporarily に "+" が付かない点に注意!

"hg qguard" によって各パッチに設定される『ガード』には、『正(+)のガード』と『負(-)のガード』の2種類があって、"hg qselect" による『ガード選択』と組み合わせることで、以下のようにパッチ適用が制御できる:

  • 『正のガード』は『ガード選択』された場合にのみ適用
  • 『負のガード』は『ガード選択』されない場合にのみ適用

例えば "+A", "+B", "-C" の3つのガードが設定されたパッチは、"hg qselect" によって A および B が選択され、且つ C が選択されない場合にのみ適用される。

人によっては、あまり『ガード』の利用シーンが想像できないかもしれないけれど、例えば僕の場合だと:

本番環境の特殊な機材の挙動を、テスト環境で擬似実現するための実装を MQ パッチで管理。
複数のテスト環境/機材毎に個別のパッチを作成し、それぞれに『正のガード』を設定。
テストを実施する環境/機材に応じた『ガード選択』の後にパッチを適用。

とか:

リリースブランチと開発ブランチの差分が一時的に肥大して、同一の MQ パッチでは適用が難しくなってしまった場合。
各ブランチ向けに個別パッチを作成して、それぞれに『正のガード』を設定。
適用対象ブランチに応じた『ガード選択』の後にパッチを適用。

といった運用をしていた。

MQ パッチで適用する変更内容も成果物に含めて良いなら、もうちょっと根本的な (= 環境依存性を下げる) 対応をするのだけれど、受託開発の場合、発注元がその手の成果物の混入を嫌がるケースが多々あるのだ。

後者の運用に関しては:

リリースブランチ向けパッチには『正のガード』(e.g.: "+RELEASE")を、開発ブランチ向けパッチには同名の『負のガード』(e.g.: "-RELEASE") を設定。
『ガード選択』の有無に応じて、必ずどちらかが適用される。

という運用方法も考えられる。

どちらを選択するかは、状況&趣味に応じて、というところかな?

TokyoMercurial #1 に参加した Kouichi Akatsuka 氏によるエントリでも、qguard/qselect に関する言及アリ。