Mercurial でバージョン管理しているファイルを Mercurial を通さずに改名したときに変更前ファイルが追跡できなかったときのメモ *1
普通は追跡できる
[shrimp]$ hg init hoge; cd hoge # 適当にファイルを作ってコミット [shrimp]$ echo 'hoge' > a.txt [shrimp]$ hg add adding a.txt [shrimp]$ hg commit -m "add a.txt" # Mercurial を通さずにファイル名を変更 [shrimp]$ mv a.txt b.txt # 変更前ファイルの削除と変更後ファイルを登録してコミット [shrimp]$ hg addremove adding b.txt removing a.txt [shrimp]$ hg commit -m "a.txt rename to b.txt" # b.txt の変更履歴を見る # 改名前の a.txt を作成したリビジョン0も出力される [shrimp]$ hg log --follow --template '{rev} {desc}\n' b.txt 1 a.txt rename to b.txt 0 add a.txt
キーワード拡張を使うと追跡できない
キーワード拡張の設定はこんな感じ。
[shrimp]$ cat .hg/hgrc [extensions] keyword = [keyword] **.txt = [keywordmaps] Header = {file|basename} {node|short}
こうしておいてファイルの中に $Header$ と書いておくと $Header: a.txt 714c62379545 $ みたいに展開してくれるのだが、こうしておいて先ほどと同じようにしても今度はファイル名変更前の a.txt を作成したリビジョン0 が出力されない。
[shrimp]$ hg init fuga; cd fuga # ./.hg/hgrc にキーワード拡張を設定 # 適当にファイルを作ってコミット [shrimp]$ echo '$Header$ ほげほげ' > a.txt [shrimp]$ hg add adding a.txt [shrimp]$ hg commit -m "add a.txt" # Mercurial を通さずにファイル名を変更 [shrimp]$ mv a.txt b.txt # 変更前ファイルの削除と変更後ファイルを登録してコミット [shrimp]$ hg addremove adding b.txt removing a.txt [shrimp]$ hg commit -m "a.txt rename to b.txt" # b.txt の変更履歴を見る # 改名前の a.txt を作成したリビジョン0が出力されない [shrimp]$ hg log --follow --template '{rev} {desc}\n' b.txt 1 a.txt rename to b.txt
解決方法
addremove するときに --similarity オプションを指定すればいい。
[shrimp]$ hg init piyo; cd piyo # ./.hg/hgrc にキーワード拡張を設定 # 適当にファイルを作ってコミット [shrimp]$ echo '$Header$ ほげほげ' > a.txt [shrimp]$ hg add adding a.txt [shrimp]$ hg commit -m "add a.txt" # Mercurial を通さずにファイル名を変更 [shrimp]$ mv a.txt b.txt # 変更前ファイルの削除と変更後ファイルを登録してコミット # このとき --similarity オプションを指定する [shrimp]$ hg addremove --similarity 1 adding b.txt removing a.txt recording removal of a.txt as rename to b.txt (37% similar) [shrimp]$ hg commit -m "a.txt rename to b.txt" # b.txt の変更履歴を見る # 改名前の a.txt を作成したリビジョン0も出力される [shrimp]$ hg log --follow --template '{rev} {desc}\n' b.txt 1 a.txt rename to b.txt 0 add a.txt
まとめ
--similarity オプションは、ファイルの類似度をパーセンテージで指定して改名検知するためのオプション。指定しない場合は100が指定されたものとみなされて、完全一致するファイルのみが改名とみなされる。キーワード拡張を使っているときに Mercurial を通さずに改名するとキーワード部分が一致しないため改名検知されない。しかし、リファクタリングで改名した場合などはそれが明らかであるから、--similarity オプションで意図的に類似度を下げて Mercurial に改名を検知させればいい *2