てもとツール
ガイド

.gitignoreが効かない原因と確かめ方|5つを順に切り分ける

.gitignore に書いたのに外れないときは、まず Git がそのファイルを記録済みかを確かめます。git status・git ls-files・git check-ignore -v の 3 つで 5 つの原因を切り分ける手順と、git rm --cached の注意をまとめました。

公開読了目安 約6分

この記事の要点

  • .gitignore は、Git がまだ記録していないファイルにだけ効く
  • 記録済みかどうかは git ls-files で確かめる
  • 効いている行は git check-ignore -v で、ファイル名と行番号まで出る
  • フォルダごと外した場所の中は、! の行で戻せない
  • git rm --cached を含む変更を取り込むと、他の人の手元からそのファイルが消えることがある
目次

.gitignore に書いたのにファイルが外れないとき、まず疑うのは「Git がそのファイルをすでに記録している」ことです。 .gitignore は、まだ記録していないファイルにだけ効きます。

記録していないのに外れないなら、書いた行がそのファイルに当たっていないか、別の行や別の場所の設定に負けています。 この記事では、Git の表示を 3 つ見るだけで、原因を 5 つのどれかに絞る手順をまとめます。

コマンドの出力は、手元の Git 2.43.0 で実際に試したものです。

まず git status の表示で分ける

最初に、困っているファイルが git status --short --untracked-files=all でどう出るかを見ます。 出方によって、次に見る場所が変わります。

  • M 付きで出る(例: M config.local): Git がすでに記録しているファイルです。原因 1 に進みます。
  • ?? 付きで出る(例: ?? debug.log): 記録されておらず、無視もされていません。どの行にも当たっていないか、! の行で戻されています。下の git check-ignore -v で見分けます。
  • 何も出ない: 無視されているか、記録済みで変更が無いかのどちらかです。下の 2 つのコマンドで見分けます。

--untracked-files=all を付けるのは、新しいフォルダの中身をファイルごとに出すためです。 付けないと、?? logs/ のようにフォルダの名前だけでまとめて出ます。

「何も出ない」の 2 つは、status だけでは区別できません。 そこで次の 2 つを順に打ちます。

git ls-files config.local        # 名前が出れば、記録済み
git check-ignore -v config.local # 出れば、無視している行が分かる

git ls-files に名前が出たら記録済みなので、原因 1 です。 git check-ignore -v は、無視している行の出所を「ファイル名:行番号:書いた行」の形で出します。

check-ignore の出力分かること
何も出ないどの行にも当たっていない
.gitignore:7:logs/7 行目が決め手
.gitignore:2:!keep2 行目の ! で戻されている
.git/info/exclude:7:…別の場所の設定

記録済みのファイルについては、git check-ignore は何も出しません。 試すと、.gitignore に書いた記録済みのファイルでも、出力は空でした。

原因 1: すでに記録しているファイル

一度コミットしたファイルは、あとから .gitignore に書いても変更を追われ続けます。 公式のマニュアルも、.gitignore は記録していないファイルのためのものだと書いています。

記録済みで、しかも .gitignore の行に当たるファイルは、まとめて一覧にできます。

git ls-files -ci --exclude-standard

外すには、git rm --cached で記録だけを消してからコミットします。 手元のファイルそのものは残ります。

git rm --cached config.local
git commit -m "config.local の記録をやめる"

原因 2: 書いた行がそのファイルに当たっていない

git check-ignore -v が何も出さないなら、どの行もそのファイルに当たっていません。 よくあるのは次の 4 つです。

  • / の位置: /dist は一番上の dist だけを指します。src/dist には効きません。
  • 末尾の /: build/ はフォルダの build にだけ当たり、同じ名前のファイルには当たりません。
  • 見えない文字: 行頭の空白・行末のタブ・全角スペースは、名前の一部として読まれます。行末のタブを付けた行は、試すと何も外しませんでした。
  • 区切りの \: docs\draft の \ はフォルダの区切りではありません。/ で書きます。

見えない文字は、エディタで見ても気づきにくいところです。 .gitignoreテスターに貼ると、こうした行に注意が付き、タブや空白を記号にして見せます。

原因 3: ! の行が、フォルダごと外した行に負けている

! で残したいファイルなのに、git check-ignore -v がフォルダの行を出すことがあります。

$ git check-ignore -v logs/keep.log
.gitignore:1:logs/	logs/keep.log

.gitignore が logs/ と !logs/keep.log の 2 行だけのときの出力です。 決め手は 2 行目の ! ではなく、1 行目の logs/ です。 Git はフォルダごと外した場所の中を見に行かないので、中のファイルを ! で戻せません。

直し方は、フォルダではなく中身を外す書き方に変えることです。

logs/*
!logs/keep.log

logs/* は logs の中身だけを外すので、logs フォルダ自体は残ります。 そのため、次の行の ! が効きます。

原因 4: .gitignore の置き場所と名前

.gitignore は、置いたフォルダより下にだけ効きます。 sub/.gitignore に *.tmp と書いても、一番上の a.tmp は外れませんでした。

ファイル名も確かめます。 .gitignore.txt のように後ろに拡張子が付いていると、Git は読みません。

原因 5: 別の場所の設定が外している

逆に「外したくないのに外れている」ときは、.gitignore 以外の設定が原因のことがあります。 Git は、リポジトリの中の .git/info/exclude も読みます。 個人の設定(core.excludesFile で指定したファイル)も同じです。

この場合も、git check-ignore -v の出所の欄に、そのファイルの名前が出ます。 試すと、.git/info/exclude:7:notes.md のように出ました。

この 2 つは、push してもほかの人には届きません。 チームで共有したい行は、リポジトリの .gitignore に書きます。

確かめる順番

迷ったら、次の順に打てば、5 つの原因のどれか(または ! の行で戻されているか)に絞れます。

  1. git status --short --untracked-files=all で、M か ?? か、何も出ないかを見る
  2. git ls-files ファイル名 で、記録済みかを確かめる(出れば原因 1)
  3. git check-ignore -v ファイル名 で、決め手の行と出所を見る(何も出なければ原因 2 か 4、フォルダの行なら原因 3、.gitignore 以外なら原因 5、! で始まる行なら下のメモ)

3 の結果を読んでも、どの行をどう直せばよいか分からないときがあります。 そんなときは、.gitignore とファイル名を .gitignoreテスターに貼ります。 直した行で結果が変わるかを確かめてから、本物を書き換えると安全です。

関連記事

参考・出典

本記事は上記の公的機関・公式情報源を参考にしています。最新の情報は各リンク先をご確認ください。

あわせて読みたい

同じテーマ・関連ツールの記事です。