Mercurial 勉強中 (3) - .hgignore で無視リスト
要旨
SCM にはバージョン管理の対象外としたいファイルを指定するのに「無視リスト」という機能があります。
- Subversion では
svn:ignore
プロパティにより無視リストを指定する- このため,
cp
やmv
時に無視リストも引き継がれる - また,あくまで
svn:ignore
プロパティの設定されたディレクトリ直下のパスが対象となる
- このため,
- Mercurial では Working directory 直下の
.hgignore
ファイルにより無視リストを指定する - 指定方法は
glob
(シェルのワイルドカード風)とregexp
(正規表現)の 2 通りがある- 混在可
- 用途により使い分けるとよい
*.tmp
等,ある拡張子のファイルをすべて無視するのならglob
- ダイレクトな指定や複雑な指定なら
regexp
Subversion における無視リスト
Subversion の場合,ディレクトリに付与された [http://subversion.bluegate.org/doc/ch07s02.html#svn.advanced.props.special.ignore:title=svn:ignore]
プロパティによって無視リストを指定します。
実例を。まずいくつかのファイルをおいてみます。
[svn]% mkdir -p a/b [svn]% svn add a A a A a/b [svn]% touch a/1.txt a/2.bin a/b/3.txt [svn]% svn status ? a/1.txt ? a/2.bin A a ? a/b/3.txt A a/b
次に,「a というディレクトリ内部の *.txt
というファイル」をバージョン管理対象から外してみます。
[svn]% svn propset svn:ignore '*.txt' a property 'svn:ignore' set on 'a' [svn]% svn status --no-ignore ? a/2.bin I a/1.txt A a ? a/b/3.txt A a/b
a
ディレクトリの下の 1.txt
は無視されていますが,サブディレクトリの a/b
内部の 3.txt
というファイルは無視されていません。つまり,Subversion の無視リストは下位ディレクトリに波及しません。
ちなみに,上記のように「--no-ignore
」というオプションをつけると,無視リストに入ったファイルも含めてステータスを確認することができます。
Subversion の場合,無視リストはあくまでディレクトリに付与されたプロパティなので,cp
や mv
した場合に無視属性が引き継がれます。
[svn]% rm a/2.bin a/b/3.txt [svn]% svn ci -m "Initial import" Adding a Adding a/b Committed revision 1. [svn]% svn cp a x A x [svn]% svn propget svn:ignore x *.txt [svn]% touch x/5.txt [svn]% svn status --no-ignore I a/1.txt I x/5.txt I x/1.txt A + x
x
ディレクトリには明示的に svn:ignore
プロパティを指定していないのですが,svn cp
した時にプロパティもコピーされたため,x
ディレクトリ直下の *.txt
も無視されるようになっています。
Mercurial における無視リスト
Mercurial の場合の実例を。
[hg]% mkdir -p a/b [hg]% touch a/1.txt a/2.bin a/b/3.txt [hg]% hg status ? a/1.txt ? a/2.bin ? a/b/3.txt
a や a/b というディレクトリ単体がバージョン管理対象に含まれていないのは Mercurial の特徴です(⇒Mercurial は空ディレクトリを管理対象に含めることができない - daily dayflower)。
Mercurial で無視リストを指定するには,Working directory 直下の .hgignore
というファイルに無視したいファイルのパターンを記述していきます。
ここで,「*.txt
」というファイルを管理対象から外してみます(下記 ^D
という表現は,CTRL+D
を入力して EOD
をしていることを示します)。
[hg]% cat > .hgignore syntax: glob *.txt ^D [hg]% hg status ? .hgignore ? a/2.bin
syntax: glob
というのはシェルのワイルドカードと同じような形式で指定する,という意味です(詳しくは hgignore を参照)。全下位ディレクトリにいたるまで,指定されたパターンにマッチするファイルが管理対象から外されていることがわかります。ここ,Subversion と違うところですね。
ところで svn status --no-ignore
と同じように無視対象のファイルも表示するためには,hg status -A
というオプションを指定します。
[hg]% hg status -A ? .hgignore ? a/2.bin I a/1.txt I a/b/3.txt
表示形式は Subversion と同じかんじです。
regexp で無視リストを設定する
では,たとえば a
というディレクトリの直下の *.txt
だけを無視したい場合にはどうするか。このときは,syntax: regexp
で対象ファイルを正規表現で指定することになります。
[hg]% cat > .hgignore syntax: regexp ^a/[^/]*\.txt$ ^D [hg]% hg status ? .hgignore ? a/2.bin ? a/b/3.txt
複雑な正規表現になってしまっていますが,無事 a/b/3.txt
が無視対象からはずれました。
glob
syntax でもパスコンポーネントを指定できる
syntax: glob
の場合,一般的にはある拡張子のファイルだけ無視する,などの使い方が向いています。ですがディレクトリを含んだ指定をすることもできます。
[hg]% cat > .hgignore syntax: glob foo/bar [hg]% hg status -A ? .hgignore I foo/bar/baz.txt ? foo/baz.txt ? hoge/bar
この指定例では「fuga/foo/bar/moge.txt
」なども無視対象になってしまうので,実用上は混乱を招くと思います。
無視対象のファイルを add
する
無視リスト,というのは,あくまで status
/ add
/ push
等時にデフォルトで対象とはしませんよ,という意味しかありません。
ですので無視リストの対象となっているファイルを hg add
することもできます。
[hg]% hg status -A ? .hgignore ? foo/baz.txt I foo/bar/baz.txt I hoge/bar [hg]% hg add foo/bar/baz.txt [hg]% hg status -A ? .hgignore ? foo/baz.txt A foo/bar/baz.txt I hoge/bar
ちなみに Subversion でも同じように無視対象のファイルを svn add
できます。
Mercurial の無視リストの注意点
0.9.3 以前ですと,syntax: regexp
で正規表現が slash で終わる場合,その trailing slash が無視されるため意図しない挙動となるようです。詳しくは 夜でもアッサム: mercurialでディレクトリをhgignoreに追加するときの注意 をご参照ください。
まとめ
Subversion の場合,プロパティという概念がある*1ので無視リストの指定もシステマティックで洗練された仕組みになっています。
それに対し,Mercurial は単一のファイルで指定するというシンプルな仕組みです。コードメンテナが自己責任で全体管理してねというスタンスといえるかもしれません。少人数で扱う小規模なレポジトリであれば,管理の手間が少ない分,楽かもしれません。
*1:バージョン管理システムというより,もはやモダンな OS でのファイルシステムのようですね。実際 DAV と絡めてファイルシステムとして利用可能ですし。