[Git] .gitignoreの仕様詳解

  • 526
    いいね
  • 0
    コメント

基本

.gitignoreを使うと無視する(Gitのトラッキングの対象外とする)ファイル or ディレクトリを指定できる。

.gitignoreは複数のディレクトリに置くことができる。
深い階層の.gitignoreに書かれた指定の方が優先順位が高い。(後に解釈される)

.gitignore内の記述は上の行から順に以下のように解釈される。

/を含まない行(fileなど)
.gitignore以下の全サブディレクトリ下にあるこの名前のファイル or ディレクトリを無視する
末尾以外にのみ/を含む行(/file, /path/to/file, path/to/fileなど)
.gitignoreが置いてあるディレクトリをカレントディレクトリとする相対パスで指定されるファイル or ディレクトリを無視する
先頭の/はルートを意味せず単に無視される
末尾だけ/な行(directory/など)
.gitignore以下の全サブディレクトリ下にあるこの名前のディレクトリを無視する
末尾以外にも末尾にも/を含む行(/directory/, /path/to/directory/, path/to/directory/など)
.gitignoreが置いてあるディレクトリをカレントディレクトリとする相対パスで指定されるディレクトリを無視する
先頭の/はルートを意味せず単に無視される
!で始まる行(!/path/to/fileなど)
!以降のパターン文字列が示すファイル or ディレクトリを無視しない
前の無視指定を上書きする
以降の無視指定に上書きされうる
空行 or #で始まる行
解釈されない

ワイルドカード

.outという拡張子のファイルをまとめて無視したい場合*.outのように記述できる。
このようなワイルドカードの類には以下のようなものがある。

*
/以外の0文字以上の文字列にマッチ
シェルのパス名展開で使われる*と同じ意味
?
/以外の1文字にマッチ
シェルのパス名展開で使われる?と同じ意味
[0-9]など
/以外の指定した1文字にマッチ
シェルのパス名展開で使われる[0-9]などと同じ意味
**
0個以上のファイル or ディレクトリにマッチ
例えば/a/**/a, /a/x, /a/x/yなどにマッチし、/**/b/b, /x/b, /x/y/bなどにマッチし、/a/**/b/a/b, /a/x/b, /a/x/y/bなどにマッチする
Git 1.8.2以降で使用可能

おすすめの書き方

# 特定の拡張子を無視する場合はどこにも/を付けない
*.o

# 特定のファイルを無視する場合は先頭に/を付ける
/npm-debug.log

# 特定のディレクトリを無視する場合は先頭と末尾に/を付ける
/bin/

gibo使っとけという話ではあるのだが、.gitignoreに自分で手を入れないといけなくなったときはこんな感じで書くと良い。

応用編: ディレクトリの罠

次のようなディレクトリ構成を考える。

├.gitignore
└tmp
  ├.gitkeep
  ├gomi
  ├gomi2
  └gomi3

/tmp/.gitkeepだけは例外として、tmpディレクトリの中身を全て無視したいと考えたとき、どういう.gitignoreを書けばいいだろうか?
次のように書きたくなるが、これは誤りである。

間違い
/tmp/
!/tmp/.gitkeep

何故なら、Gitはパフォーマンス上の理由から、ディレクトリを無視した場合、そのディレクトリ中の一部のファイルやディレクトリだけを無視しないようにすることはできないという制限を設けているからだ。
よって、こう書く必要がある。

正解
/tmp/*
!/tmp/.gitkeep

「tmpディレクトリ」を無視してからその中の特定のファイルだけ除外しているのではなく、「tmpディレクトリ中の全てのファイルやディレクトリ」を無視してから特定のファイルだけ除外していることに注目してほしい。
これならば制限に引っかからずにやりたいことを実現できる。

より複雑なケースでも考え方は同じだ。
次のディレクトリ構成で、/tmp/deep/directory/.gitkeepだけは例外として、tmpディレクトリの中身を全て無視したい場合を考える。

├.gitignore
└tmp
  ├deep
  │├directory
  ││├.gitkeep
  ││└gomi
  │└gomi2
  └gomi3

この場合、(面倒だが)こう書く。

複雑なケース
/tmp/*
!/tmp/deep/
/tmp/deep/*
!/tmp/deep/directory/
/tmp/deep/directory/*
!/tmp/deep/directory/.gitkeep

前述の制限を巧妙に回避していることを確認してみてほしい。

ちなみに、Gitのバージョン2.7.0だけは、上の複雑なケースを次のようにシンプルに書ける機能を搭載していて、一時期話題になった。

Git-2.7.0限定
/tmp/
!/tmp/deep/directory/.gitkeep

ところがこの機能は一部状況下ではうまく動かないことが明らかになったため、Git 2.7.1以降ではrevertされている。
Git 2.7.0の新機能を中途半端に知っていた人は気を付けよう。

その他

\でエスケープできる。

# Emacsの自動保存ファイルを無視する
\#*#

参考リンク

git/gitignore.txt at v2.10.2 · git/git