彷徨えるフジワラ

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

1.8 版以降の Mercurial を推奨

SSH 経由でリモートリポジトリと連携する際に、(1) 連携先ホストのシステムワイドに使用可能 (例: /usr/bin/hg 等) な hg コマンドのバージョンが低い一方で、(2) 連携先リポジトリhg init で使用した hg コマンド (例 ${HOME}/usr/local/bin 配下に独自インストールしたもの) のバージョンが、ある程度新しいものである場合、連携先リポジトリの指定が正しくても、以下のようなエラーメッセージが表示される可能性があります。

there is no Mercurial repository here (.hg not found)!

※ 日本語出力の場合:
Mercurial リポジトリが見つかりません(.hg が不在です)

以下の2つのバージョンで、前者のみが 1.7 以前の場合は、まず間違いなくこの問題に該当するものと思われます。

  • ssh username@hostname hg version で表示される hg コマンドのバージョン
  • ssh username@hostnameログインした状態での hg version で表示される hg コマンドのバージョン


理想的な対処方法としては:

クライアント側/サーバ側共に、システムワイドにインストールするのは 1.8 版以後の Mercurial を推奨

但し、1.8 版には『名前付きブランチを fast-forward merge してしまう』問題があるので、厳密には『1.8.1 版以降を推奨』することになります (最新の情報に関しては、こちらのエントリを参照してください)。

以下、対処方法や問題の原因に関する詳細です。

対処方法

問題解消の選択肢としては:

  1. /usr/bin/hg 等のシステムワイドにインストールされる Mercurial を、適切なエラーメッセージを表示する 1.8 版以降にアップデートする
  2. ssh 連携の際には、 "--remotecmd /usr/local/bin/hg" (あるいは、設定ファイルでの "[ui] remotecmd=/usr/local/bin/hg" 記述)で、明示的に hg コマンドを指定
  3. リモートホスト上では、少なくともリポジトリ初期化の時だけでも /usr/bin/hg を使う (以後の操作は、独自インストール版を使用可能)
  4. リモートホストのユーザ固有のシェル設定ファイルをちゃんと書く

OS のディストリビューションによっては、古い版の Mercurial しかパッケージとして提供していないケース(例: CentOS は未だに 1.4 版を提供)もあるので、(1) は、環境次第で選択できない可能性があります。

(2) は、リポジトリ毎の連携先ホストが単一であれば、妥当な選択肢でしょう。

hg init でのリポジトリ作成では、URL として ssh アクセス先(例: "ssh://host/path/to/new/repo")を指定することも可能なので、初期化だけは非対話的に実施(= /usr/bin/hg 等のシステムワイドなものが使用される)というルールを守れるのであれば、(3) の選択肢は、まぁまぁ妥当と言えなくもないでしょう。

設定ファイル周りの話は少々面倒ではありますが、エンドユーザレベルで確実なのは、(4) の選択肢と言えるかもしれません (ユーザ固有のシェル設定ファイルの記述が、どのように問題解消に結びつくのかは後述)。

問題の詳細

Mercurialssh 連携は、SSH の非対話的コマンド実行を使って、サーバ側で起動した "hg serve" プロセスと、クライアント側 hg コマンドとの通信、として実現されています(--verbose オプション付きで実行してみると、非対話実行されるコマンドの内容が表示されます)。

しかし、ユーザ固有の設定 (例: ${HOME}/.bashrc${HOME}/.profile) の記述次第では、対話的実行と非対話的実行では、環境変数 PATH の設定が異なってしまうことで、それぞれのケースでインストール先の異なる hg コマンドが実行されてしまう可能性があります(詳細は、こちらを参照のこと)。

  • SSH 経由でサーバにログインして "hg init" する際に使用される hg コマンド ⇒ 自前でインストールした hg コマンド
  • "hg push ssh://remote/path/to/repo" の際などに、サーバ側で実行される hg コマンド ⇒ システムワイドな hg コマンド (/usr/bin/hg 等)

Mercurialリポジトリは、"hg help config" の format セクションを見ればわかるように、旧版との互換性が無い拡張を何度か実施しています。

    "usestore"
        ファイル名の文字大小を認識しないようなファイルシステムへの、
        適応性を向上させる、 "store" 形式リポジトリの使用可否。
        デフォルトでは有効化されています。 この設定を無効化した場合、
        新規作成したリポジトリは、 0.9.4 以前の Mercurial と、
        ディスク記録形式で互換性が保たれますが、 状況次第では、
        長いファイル名での保存が必要になります。

    "usefncache"
        "store" 形式リポジトリ (本設定の有効化に必須) において、
        長いファイル名を使用するための機能向上や、 "nul" のような Windows
        予約名利用を回避可能にする、 "fncache" 形式リポジトリの使用可否。
        デフォルトでは有効化されています。 この設定を無効化した場合、
        新規作成したリポジトリは、 1.1 以前の Mercurial と、
        ディスク記録形式で互換性が保たれます。

    "dotencode"
        "fncache" 形式リポジトリ (本設定の有効化に必須) において、 Mac OS X
        では "._"  、Windows では空白文字で始まるファイル名が、
        原因となって発生する問題を、 回避するための  "dotencode"
        形式リポジトリの使用可否。 デフォルトでは有効化されています。
        この設定を無効化した場合、 新規作成したリポジトリは、 1.7 以前の
        Mercurial と、 ディスク記録形式で互換性が保たれます。

新版で作成したリポジトリを、互換性の無い旧版で直接アクセスすると:

unknown repository format: requires features 'XXXX' (upgrade Mercurial)

※ 日本語出力の場合:
未知のリポジトリ形式です: 'XXXX' サポートが必要 (要 Mercurial 更新)

といったエラーが表示されます。

しかし、1.8 版までの Mercurial には、SSH 経由でアクセスする clone/push/pull/incoming/outgoing 等において、本来上記のようなエラー表示をすべき状況で:

there is no Mercurial repository here (.hg not found)!

※ 日本語出力の場合:
Mercurial リポジトリが見つかりません(.hg が不在です)

と表示してしまう障害があるのです。

つまり、リモートホスト側の hg コマンドが 1.8 よりも前の版だった場合、特に dotencode フォーマット拡張が実施された 1.7 よりも前の版であれば、SSH 経由アクセスでエラーが発生した際に、それが本当に『パス指定が間違っていた』ことによるエラーなのか、それとも『hg コマンドの版が古くてアクセスできない』ことによるエラーなのかを区別することができません。

単に分からないだけならまだ良いのですが、これまでに説明した事情を知らない場合、そもそも『hg コマンドの版が古くてアクセスできない』ことが原因だということに思い至らない可能性が高いでしょう。

結果として、『リポジトリが見つからない』と言い張る Mercurial に対して、『リポジトリのパスは間違ってない!』と不満を募らせることになるわけです。

なお、このメッセージ不正出力問題に関して:

上記ツイートでの指摘を受けて、リモートホスト上の Mercurial が旧版の場合でも、クライアント側で相応のヒント情報を表示する提案をしてみたのですが:

頑張ってサーバ側の Mercurial を更新してもらったほうが良くねぇ?(意訳)

ということで却下されてしまいました……orz