彷徨えるフジワラ

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

リビジョン指定+ファイル名指定での hg log 挙動の障害

久々に Mercurial ネタ。とは言いつつも、事の発端となったリポジトリonnv-gate なので、Solaris ネタでもあったりする。

ちょいと必要性があって、ビルド 79 と 111 の間でヘッダファイル vnode.h や vfs.h に適用された変更内容を確認することに。

リビジョン間の差分に関しては、以下の要領で簡単に取得可能。

$ hg diff -r onnv_79 -r onnv_111 usr/src/uts/common/sys/vnode.h
    .....

で、差分は把握できたので、どういう経緯で変更されたのかを確認しようと、コミットログの一覧を得るべく、"hg log" を以下の要領で実行。

$ hg log -r onnv_79:onnv_111 usr/src/uts/common/sys/vnode.h
$

.... はぁ?!何で何も出力されないの? > hg log
同一変更を複数ブランチで実施するようなケースでは、個々のファイルでの差分管理において差分情報が統合されるため、ファイル名を指定した "hg log" 出力が期待と異なる場合があることは承知しているのだけど、基本 onnv-gate は一本道な履歴なので、このケースには当てはまらない筈。

一応、上記のケースへの対処方法と同様、-k の引数にファイル名を指定すると期待通りにコミットログが出力される。しかし、それはちょっと納得行かないなぁ。

ということで、隙間時間を使って地道にデバッグしてみることに。

まずは "hg debugindex" を使って、対象ファイルの差分管理情報(filelog)を覗いてみることに。

$ hg debugindex .hg/store/data/usr/src/uts/common/sys/vnode.h.i
   rev    offset  length   base linkrev nodeid       p1           p2
     0         0    9945      0       0 91660f6da543 000000000000 000000000000
     1      9945     144      0     254 04b213323838 91660f6da543 000000000000
     2     10089      12      0     569 c22935ffb103 04b213323838 000000000000
     3     10101      59      0     789 6daa06c0c278 c22935ffb103 000000000000
     4     10160     980      0    1488 160b88f62b44 6daa06c0c278 000000000000
     5     11140      12      0    1925 62027866446b 160b88f62b44 000000000000
     6     11152     136      0    3290 edcdc88349e1 62027866446b 000000000000
     7     11288    1047      0    3898 a35b8102ba8f edcdc88349e1 000000000000
......

revlink 欄が、変更に対応するリポジトリのリビジョン番号。

"hg tags" の出力からは、作業中のリポジトリにおいて onnv_79=4ed96167d864(rev=5530)、onnv_111=fdba8b9800fa(rev=9062) であることが、-k 付きの "hg log" 実行からは、想定対象のリビジョン番号が 5599, 6264, 6492, 6712, 6976, 8190, 8433 であることがわかっている。

で、debugindex 出力と付き合わせて見る限りでは、想定対象リビジョンはちゃんと認識できそうな感じ > filelog

ふーむ、そうなると filelog を走査する処理に問題があるのだな。

"hg log" 実装を読み込む事暫し.... cmdutil.py の walkchangerevs() における wanted 集合に追加されたリビジョンが、表示対象になる模様。ファイルを指定した場合は "not slowpath" ルートになることもわかった。

後はもう、repo.ui 経由でいわゆるデバッグ print 実施、という泥臭い方法で絞り込む。っつーか、一人前の Pythonista はデバッガとかを使うのかな?半人前な私にどなたかご教授を (^ ^;;;)

内部関数 filerevgen() は、-r で指定されたリビジョン範囲を正しく扱えているみたいなのだが、肝心の filerevgen() で for ループを回した結果として、wanted 集合に何も追加されていない! どうやら "rev not in ancestors" 判定での continue が、wanted への追加を阻害している模様。

    ancestors = set([filelog.linkrev(last)])

    for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
        if rev not in ancestors:
            continue

"--follow" 指定と関係無い場合、last 値は filelog の末尾を指す値になることから、ancestors 集合の初期値は、対象ファイルが改変された最後のリビジョンのみが含まれる状態になる筈。

でも今回のケースでは、-r 指定による絞込みの影響で、filerevgen() が生成するシーケンスには「対象ファイルが改変された最後のリビジョン」が含まれないから、そもそも rev in ancestors が成立する筈が無い。っていうか、この判定って何の意味があるの?

試しにこの判定処理を外してみると....やった!期待通りの出力が!やっぱりお前だったか > "rev not in ancestors"

とりあえず、最新版のソースでも動作確認してみよう....あれ?直ってる!

"hg grep" してみると....あぁ、issue 2492 対応で修正されていたのか。リリース状況で見ると 1.7.1 版で修正が取り込まれているのね。

バグが入り込んだのは 99cafcae25d9 あたりのようなので、リリース的には 1.6.3 以後に含まれているのか。どうやら、--follow 系での問題に対処するつもりで、筆が滑った感じだなぁ > 99cafcae25d9

結局、仕事環境で使っている hg コマンドが、去年 1.6.4 をインストールして以来、立て込んでいたせいで更新してなかったのが問題、という結論に .... orz