作業途中成果の push 防止
TokyoMercurial #3 の懇親会において、@cointoss1973 氏から以下の様な相談が:
MQ パッチを "qpop -a" して、再度 "qpush -a" する際に、適用先リビジョンが変わってしまうのは、なんとかならないだろうか?
最初に相談された時には、何の事やらワケワカで「???? 」な状態だったのだが、お互いの前提条件に関して、色々刷り合わせを行った結果、以下の様なユースケースであることが判明:
- ローカルリポジトリの最新版を A-base とする
- MQ を使って、A-base を元に機能 A に関して作業を実施
- 優先度の高い機能 B の作業が、割り込んで来る
- 機能 A の MQ パッチを一旦 "qpop -a"
- 共有リポジトリから最新成果を pull + 作業領域の update
- この時点の最新版を B-base とする
- B-base を元に機能 B の作業を実施 ⇒ 完了(commit) ⇒ push
- 機能 A の作業を再開しようとしても、メモしてないと A-base が不明
- B-base に対して "qpush -a" すると衝突発生の可能性が…
- でも "qpop -a" でパッチを外しておかないと、(7) で中途成果が push されてしまう
- さて、どうしたものか?
@cointoss1973 氏の当初の要望としては:
MQ が適用先リビジョンに関する情報を覚えておいて欲しい or それに類する機能は無いか?
というものだったのだが、それをやってしまうと、折角の『任意のリビジョンに移動して適用可能』という MQ の特性が失われてしまうので、ここは以下のように発想を変える必要がある。
やりかけの途中成果を push 対象から外す方法は無いか?
以下は『仕組み』と『運用』のそれぞれによる実現方法。
ちなみに、(9) で衝突の可能性がある場合は、再開した機能 A の作業を統合する際に、rebase するにしろ、merge するにしろ、衝突が発生するのは変わらないので、まぁ、その辺の手間は覚悟が必要。
『仕組み』による防止
『仕組み』による push/pull の防止は、まさに 2.1 で導入された phase 機構の出番と言える。
MQ を使用するなら以下の設定は必須と言えよう。
[mq] secret = True
この設定により、"hg qpush" で適用された MQ パッチによるリビジョンは、phase が secret 化されるため、push/pull の対象から除外される。
但し、この設定は『設定後に適用された MQ パッチ』に対して有効なので、既にパッチを適用済みの場合は、設定後に一旦パッチ適用を解除 ⇒ 再適用の必要がある。
また、MQ を使わない場合でも、"hg phase [-p|-d|-s] REV....
" コマンド実行により、手動での phase 変更が可能なので、『実験的な作業』の際にあらかじめ phase を secret にしておけば、そのリビジョンを起点とした以後の作業成果は push/pull 対象から除外される。
なお、『secret の子リビジョンは secret』の原則があるので、phase が secert な枝と public/draft な枝のマージでは、マージリビジョンは自動的に secret になるので注意。マージリビジョンを public/draft 化しようとすると、その祖先である secret にしておきたいリビジョンまで public/draft 化されてしまう。
ちなみに、自分が作業する場合は、以下の理由から、コードの特性(バグ修正/新規機能/実験的変更 etc)に関わらず、普通にコミットする方が多かった気がする。
名前無しブランチとして枝分かれ (= マージされていない) していて、共有リポジトリに push する前なら、事後に何とでもなる (= MQ 取り込み/graft/rebase 等) ので、事前に『パッチとして利用』な事が確定している場合でもなければ、通常リビジョンとして普通にコミット
枝分かれしていれば、『ヘッドを増やす push は許さんのじゃぁ、われぇ!?』(意訳)ガードが働くので、うっかり push してしまう事も無いしね。
『運用』による防止
先のユースケースでは、push したい作業成果は『B-base を元に機能 B の作業を実施』したリビジョンだけの筈。
『機能 B の作業を実施』した場合、何らかの commit リビジョンが新規作成されているわけだから:
- 『機能 B の作業を実施』したリビジョン群と、MQ 管理下の『機能 A の作業を実施』しているリビジョン群は、名前無しブランチとして枝分かれしている
- 作業領域の親リビジョンは『機能 B の作業を実施』した側のブランチ
この場合、push 対象リビジョンとして『作業領域の親リビジョンに連なるリビジョンだけ』を以下のように指定すれば良い:
$ hg push -r .
id:troter 氏が度々 alias 指定をお勧めしている "nudge" コマンドは、まさにこのリビジョン指定での push のこと。