guide

なぜ無視される? git check-ignore でデバッグする

git check-ignore -v、git status --ignored、git ls-files で、どのルールがファイルを無視しているかを突き止め、ルールが動作しないよくある原因 7 つを点検する方法です。

ルールが増えると、「このファイルはなぜ見えないのか?」あるいは「なぜ見え続けるのか?」という疑問が生まれる。git にはこの疑問に答えてくれるコマンドがある。

git check-ignore -v

git check-ignore -v logs/app.log src/build/keep.txt

出力は ソース:行番号:パターン<タブ>パス の形式である。

.gitignore:3:*.log	logs/app.log

一致しなかったパスまで見るには、--non-matching(-n)を併用する。

追跡中のファイルには --no-index

すでに追跡中のファイルには無視ルールが適用されないため、check-ignore も既定では何も出力しない。ルールがそのファイルに一致するかどうかだけを知りたいなら、--no-index を付ける。

$ git check-ignore -v app.log            # 追跡中なので出力なし
$ git check-ignore -v --no-index app.log
.gitignore:3:*.log	app.log

無視されたファイルの一覧を見る

# 状態とともに無視された項目を表示(!! 表示)
git status --ignored --short

# 無視されたファイルをファイル単位ですべて列挙
git ls-files --others --ignored --exclude-standard

# 無視ルールに一致するのに追跡中のファイル
git ls-files -ci --exclude-standard

git status --ignored は、ディレクトリ全体が無視されると !! logs/ のようにディレクトリ 1 つとして表示する。ファイル単位で見たいなら ls-files を使う。

ルールが動作しないよくある原因

  1. すでに追跡中である。 最も多い。git ls-files <パス> に出力があれば追跡中である。git rm --cached で追跡を外す。
  2. 親ディレクトリが除外されている。 dir/ を無視した状態では !dir/file は効果がない。dir/* に変える。
  3. 順序が逆になっている。 否定ルールの後により広いルールが再び現れると、そのルールが勝つ。check-ignore -v の行番号を見ればすぐにわかる。
  4. 末尾の空白。 *.log の末尾の空白は取り除かれるが、逆にパターンのの空白や全角スペースのような目に見えない文字は、パターンの一部として残る。
  5. スラッシュの向き。 gitignore は Windows でも / だけをパスの区切り文字として使う。build\output はバックスラッシュがエスケープとして解釈され、意図どおりに動作しない。
  6. アンカリングの思い違い。 config/local.json は途中のスラッシュのため、ルートの config にのみ一致する。あらゆる深さに適用するには **/config/local.json を使う。
  7. 大文字と小文字。 core.ignorecasefalse の環境(通常は Linux)では、*.JPG*.jpg は別物である。macOS・Windows で作ったリポジトリはたいてい true なので、ローカルでは効くのに CI では効かないという差が生じうる。

ブラウザーで事前に確認する

リポジトリに適用する前にルールを変えながら結果を比べたいなら、このサイトのパターンテストタブが便利である。ルールとパスの一覧を貼り付けると、パスごとに結果と決定したルール(行番号)、親ディレクトリが原因で無視された場合を表示する。パスの一覧は git ls-filesfind . -type f の出力をそのまま使えばよい。ただし、下位ディレクトリの .gitignore やグローバル設定まで合わせた最終判定は、リポジトリで git check-ignore -v を使って確認する。

参考

← 前へすでにコミットしたファイルを .gitignore で無視する