Mercurial: "Finding and fixing your mistakes" を読む
Tagged:  •    •  

今回は "9. Finding and fixing your mistakes" を読みます。

9.1 Erasing local history
9.1.1 The accidental commit

読者に対する社交辞令かもしれませんが、 考えるより先に手が動くせいで、 Bryan O'Sullivan 氏もちょくちょく構成管理を間違えるそうです。

9.1.2 Rolling back a transaction

他のリポジトリに更新を反映する前なら、 直前に実施した commit の実行を hg rollback で取り消せます。

他のリポジトリに push したり、 別な変更を commit したりする前に、 自分が間違っていることに気が付けるように、 commit 直後の status 確認を心がけましょう。

commit 直後の status 確認のお陰で、 私も何度か危ういところを救われたことがありますし、 つい今しがたも、 確認を怠った同僚が間違ったチェンジセットの rollback の機会を逸して orz となっておりました。

9.1.3 The erroneous pull

「直前の1回分」という制約は変わりませんが、 hg rollbackpull 操作の取り消しもできます。

9.1.4 Rolling back is useless once you’ve pushed

原文では、「一旦共有リポジトリ等に push された変更は、野に解き放たれたようなものなので、 (余程条件が揃わない限りは)無かったことにはできない」 というスタンスですが、 多数の開発者が遠隔地間で連携する OSS 系開発なら兎も角、 同一のタイムゾーン下に居て、電話をすればすぐに繋がる (あるいは直接会える)メンバーとの開発なら、 必ずしもそうとは限らないと思います。

もっとも、 生活サイクルのタイムゾーンが違ったり、 数十人が直接共有リポジトリにアクセスするような状況であれば、 やはり諦めた方が良いのかもしれません。

9.1.5 You can only roll back once

「何度も言うけど rollback できるのは、 直前の1回分の操作だけだよ」というお話。

9.2 Reverting the mistaken change

hg rollback が取り消すのは commitpull による「チェンジセット増加操作」で、 hg revert が取り消すのは 「ファイル毎操作」(内容の変更含む)です。

9.2.1 File management errors

hg revert は、 addremovecopy および rename の取り消しもできます。

ちなみに add の取り消しは、 以前は forget で行っていましたが、 現在では revert に統一されています (ちょっと前までは警告付きで使えた)。

9.2.1.1 A slightly special case: reverting a rename

hg rename は内部的には hg copyhg remove の組み合わせですから、 変更後のファイル(hg copy 先)に対してだけでなく、 変更前のファイル(hg remove 対象) に対しても revert する必要があります。

9.3 Dealing with committed changes

この節では、 履歴途中の変更の「効果」(= 修正内容)を hg backout により取り消す遣り方を説明しています。

9.3.1 Backing out a changeset

この節では、 動作確認用のリポジトリを作成した上で、 hg backout の起動方法を説明しています。

9.3.2 Backing out the tip changeset

一番簡単な例として、 tip チェンジセットに対して hg backout を行うことで、 tip の効果を打ち消します。

tip の backout(BOS book より引用)

実施後のファイルの内容だけを見るならば、 この節で行っていることは hg rollback と同じですが、 他のリポジトリに commit 内容が伝播した後であっても機能する点で、 hg rollback による取り消しとは異なります。

9.3.3 Backing out a non-tip change

非 tip なチェンジセットに対する hg backout 実施では、 対象となるチェンジセット(図では second change) の効果を打ち消すチェンジセット (図では backout second change)を作成し、 現時点での parent (図では third change)に対して backout second change をマージするところまでを自動的に実施してくれますから、 後は(必要に応じて衝突を解消した上で) commit するだけで、 second change の効果を打ち消した成果物を得ることができます。

非 tip の backout(BOS book より引用)

取り消すことができない 「野に解き放たれたチェンジセット」を一種のウィルスとするならば、 拡散前にウィルスを死滅させようというのが hg rollback のアプローチで、 ワクチン代わりのカウンターウィルスを解き放つことで自然死滅を狙うのが hg backout のアプローチ、 と言えるでしょうか。

9.3.4 Gaining more control of the backout process

この節の趣旨は、 "hg backout --merge" で実施される処理を手動で行ってみることで、 処理の実際を理解しようという点にあります。

9.3.5 Why “hg backout” works as it does

この節では、 hg backout 対象のチェンジセットに相当するパッチファイル (hg export 等で作成可能)を逆向きに適用 (= patch -r)する手法が、 hg backout よりも劣る理由を説明しています。

肝となるのは、 「tip に直接逆向きパッチを当てる」より、 「tip と backout チェンジセットによる 3-way マージ」の方が、 より適切な結果を得やすい、 という点にあります。

9.4 Changes that should never have been

「Mercurial は「蓄積」ベースでの構成管理なので、 一旦 commit してしまうと取り消すのは大変」 というお話。

9.4.1 Protect yourself from “escaped” changes

「共有リポジトリの incoming フックを使って、 不正なチェンジセットの push 等からリポジトリを防御しましょう」 というお話。

9.5 Finding the source of a bug

この節では、 チェンジセットの特定に bisect 拡張を使う方法を説明しています。

この節を読み始めた際は何を言っているのかさっぱりだったのですが、 bisect 拡張、凄く面白いですね。

現時点の作業領域ディレクトリの成果物が、 「ある条件を満たすか否か」の2値を調べるテストを用意したならば:

  1. bisect からのテスト対象チェンジセットの指示
  2. テストの実行
  3. bisect への結果報告

を繰り返すことで、 最終的に「ある条件を満たすか否か」 の変わり目となっているチェンジセットが特定される、 というのが bisect 拡張の骨子です。

テストの内容は利用者が自由に決定できるので:

  • バグの混入
  • パフォーマンスの急低下
  • バイナリサイズの急増

といった任意の条件での検索が可能となっています。

チェンジセット数に対して対数のオーダで特定が可能で、 履歴の枝分かれを考慮して不要なチェンジセットを検査対象から除外してくれる、 とのことで、 なかなか効率が良さそうです。

9.5.1 Using the bisect extension

この節では、bisect 拡張の実際の利用方法を、 コマンド実行例を使って説明しています。

9.5.2 Cleaning up after your search

「次回の利用に備えて、bisect reset を忘れるな」 というお話。

9.6 Tips for finding bugs effectively
9.6.1 Give consistent input

bisect へのテスト結果を正しく報告しないと、 bisect による矛盾検出にも限度が有るよ」 というお話。

9.6.2 Automate as much as possible

「手動でのテスト実行は間違い易いので、 極力自動化しましょう」というお話。

9.6.3 Check your results

bisect によるチェンジセット特定結果を全面的に真に受けないで、 (自動化した)テストを使って、ちゃんと手動で確認を行いましょう」 というお話。

9.6.4 Beware interference between bugs

「複数のバグがあると、 テストの結果にノイズが混じるので、 チェンジセット特定が上手くいかない場合がある」 というお話。

9.6.5 Bracket your search lazily

「対数オーダで特定できるから、 最悪全てのチェンジセットを検査対象にしても大丈夫」 というお話。


この章で書かれていることを一通り習得すれば、 うっかり構成管理操作を間違ってしまったり、 問題発生時点を特定する必要が発生した場合でも、 慌てずに対処できそうです。 個人的に興味深いのは、やはり bisect 拡張でしょうか (実際に使うとなると面倒臭そうですが…)。


"Distributed revision control with Mercurial" 関連エントリの一覧は、BOSBook(Bryan O’Sullivan Book)タグで参照できます。