2012年5月19日土曜日

Windows環境でのmercurial運用の注意点

小生はlinux/ubuntuなので全く気にしませんが、Windows(追記、MacOS 12.5でも経験)で使うと、独特のトラブルがあります。

「Windowsでの」大文字小文字の変更でトラブります。

こんな感じで怒られます

abort: case-folding collision between 古い方 新しい方

  • mercurialはファイルのリネームをする場合、「古い名前で削除」と「新しい名前で新規作成」を1回のチェンジセットに捻じ込みます。
  • ところが、Windowsでmergeしようとすると、新旧の名前が同時に存在できない(大文字小文字の違いだけ)ので、conflictが起こるわけです。
  • これはmercurialでは既知の問題点で、case foldingと呼んでるらしい。フツーの英語でした。

http://mercurial.selenic.com/wiki/CaseFolding
http://mercurial.selenic.com/wiki/CaseFoldingPlan
http://mercurial.selenic.com/wiki/FixingCaseCollisions

エクステンションでどうにかしようという試みもあるようですが、小生が同僚に試してもらった限りではうまくはいきませんでした。自分で試してみる気力はありません。Windowsを愛してないので。

http://mercurial.selenic.com/wiki/FixcaseExtension
http://mercurial.selenic.com/wiki/CaseFoldExtension
http://mercurial.selenic.com/wiki/CasestopExtension

mercurial内部で、改名を追跡するような対策を施す。という線もありますが、今のリポジトリ構造だとやや困難っぽいです。仮にできたとして、リポジトリの互換性が無くなるでしょう。

一方、subversionは、ファイルのリネームを追跡するらしいので、一見うまく行きそうに見えます。だからと言って、数々のデメリット を呑んでまでsubversionに戻そう。とかいうのは本質的に間違ってます。プログラマなれば、「手段」のために「手段」を選んではいけません。だってリネームやらなきゃ済む話なんだから。もしくは、大文字小文字を区別できないような駄目OSは捨てるべき

それじゃ済まないのが現場。やっちまったら仕方ありません。

本件の解決方法は、意外と簡単です。マージの対象のファイル群を、予めチェンジセット両者にcommitしておく。

defaultブランチに、casefoldブランチをマージする場合
  • hg up default
  • hg revert -r casefold ... # 改名後のファイルに強引に置き換える
  • hg commit -m "コンフリクト回避"
  • hg merge casefold
  • hg commit -m マージしますた

ただしこの作業中は、他の作業者のマージ等を止めさせる必要があります。元の木阿弥なので。中央リポジトリサーバで、case foldingを検出して、pushを断るような仕掛けをしたほうが良いかも知れません。