Mercurial のパターン指定におけるディレクトリ相対性/合致条件
本エントリも、備忘録代わりに「お気に入り」に入れておいたツィートの棚卸しシリーズの一部です(笑)
随分前になりますが、以下のツィートに関連する一連のツィートで、パターン指定に関してのやり取りがありました。
一般的な利用ケースでは、それほど踏み込んだパターン指定の必要はないと思いますが、折角ですので、文書化されていない情報を含めて、パターン指定絡みの仕様をきっちりとまとめておこうと思います。
パターンにおける「起点ディレクトリ」
以下の表は、hg help patterns
で表示されるオンラインヘルプ(ウェブ経由でも参照可能)の記載を元に、パターン形式と起点ディレクトリの関係について、簡単にまとめたものです。
パターン形式 | 名称 | 起点ディレクトリ |
---|---|---|
拡張ワイルドカード | glob |
現ディレクトリ |
正規表現 | re |
リポジトリルート |
文字列一致 | path |
リポジトリルート |
しかしこれだけでは、パターン指定の全貌を掴むのには不十分です。
起点ディレクトリに関して、文書化されていない指定形式の情報を含めて、もう少し詳しく見てみましょう。
パターン形式 | 起点ディレクトリ | ||
---|---|---|---|
現ディレクトリ | リポジトリルート | 任意(部分一致) | |
拡張ワイルドカード | glob | ---- | relglob |
正規表現 | ---- | re | relre |
文字列一致 | relpath | path | ---- |
通常のパターン指定は、特定の起点ディレクトリからのパスに対して、先頭一致であることが求められます。しかし、「任意(部分一致)」の場合は、リポジトリルート相対パスに対する部分一致のみで、そのファイルはパターンに一致したものとみなされます。
例えば、管理対象ファイル foo/bar/baz.txt
に対して、foo/bar
以外のディレクトリからは、glob:baz.txt
指定は合致しませんが、relglob:baz.txt
であれば、作業領域中のどのディレクトリにいても合致します。
このように、起点ディレクトリ(glob
であれば現ディレクトリ)と結びついている状態は、"rooted" と表現されます。relglob
や relre
は rooted ではありません。
.hgignore
における文法指定 glob
や re
は、実際には relglob
や relre
のことを指しています。つまり、コマンドラインでの glob
指定と、.hgignore
での glob
指定では、起点となるディレクトリが違うということです。
hg help patterns
や hg help hgignore
等のオンラインヘルプでも、これらの特徴に関して、備考として補足しています(2.8.2 版時点だと、翻訳版の hg help hgignore
での備考の表現は、ちょっと微妙かもしれません。2.9 版向けに直しておこうと思います)。
パターンにおける「末尾一致」
さて、先程の "rooted" の話は、起点ディレクトリからのパスに対する「先頭一致」の話と言えますが、もう一点、パスに対する「末尾一致」の話があります。
以下の表は、パターンと指定方法の組み合わせに対して、末尾一致が要求されているか否かをまとめたものです。
形式 | 名称 | 末尾一致 | |
---|---|---|---|
引数指定時 | -I /-X 指定時 | ||
拡張ワイルドカード | glob |
必要 | 不要 |
relglob |
|||
正規表現 | re |
不要 | 不要 |
relre |
|||
文字列一致 | path |
不要 | 不要 |
relpath |
末尾一致が必要なものは、管理対象ファイル名の末尾までが、指定パターンの合致範囲に含まれていなければ、合致したものとみなされません。
例えば foo/bar/baz.txt
に対して、コマンドライン引数としての glob:foo/bar
や relglob:bar
は合致しません。
その一方で、末尾一致が不要なものは、パターンの合致範囲がファイル名末尾を網羅していなくても、合致したものとみなされます。
そのため、-I glob:foo/bar
や -X relglob:bar
であれば、先述の foo/bar/baz.txt
に対しても合致とみなされます。
もしも、コマンドライン引数での指定で glob
形式を合致させたい場合は、glob:foo/bar/**
のように指定する必要があります(あるいは path:foo/bar
で代替する手も)。
この辺の微妙な差異は、代表的なユースケースにおける利便性ベースで決定されたのか、歴史的経緯(=後方互換性維持)に由来するものなのかは定かではありませんが、微妙にわかりにくい感じではありますね。
まとめ
以下の表は、これまでの情報をまとめたものです。
形式 | 名称 | 起点ディレクトリ | 末尾一致 | 備考 | |
---|---|---|---|---|---|
引数指定時 | -I /-X 指定時 | ||||
拡張ワイルドカード | glob |
現ディレクトリ | 必要 | 不要 | ---- |
relglob |
任意 | .hgignore での glob |
|||
正規表現 | re |
リポジトリルート | 不要 | 不要 | ---- |
relre |
任意 | .hgignore での re |
|||
文字列一致 | path |
リポジトリルート | 不要 | 不要 | ---- |
relpath |
現ディレクトリ | コマンドラインのデフォルト形式 |
今回色々確認した際に気付いたのですが、path
や relpath
なども末尾一致が不要なパターンであるため、正確には「厳密一致」という訳ではありませんね。個人的には、これらのパターンは「末尾合致が必要」なイメージを持っていたので、ちょっと意外でした。