ブログに戻る

Gitignoreが効かない?本当の原因と直し方

2026年9月17日

TL;DR: .gitignoreが効かないとき、そのファイルはほぼ確実に追跡済みです。gitは見たことの無いファイルしか無視しない——インデックスに入ったファイルは、どんなルールの効き目も受けません。 真相はgit check-ignore -v <path>で確かめます。出力が沈黙なら、そのパスは追跡済みで、どのルールも適用されていません。git rm --cached <path>で直してコミットすれば、無視ルールはそのコミット以降から効き始めます。残りのケースは、ルールの順序、否定(negation)の罠、VS Code由来の誤解で説明がつきます。

なぜ.gitignoreが効かないのか?

大多数のケースを1つの仕組みが説明します。ルールができる前にファイルがコミットされていた、というものです。.gitignoreはgitからファイルを隠すフィルタではありません。「未追跡の状態から何をgit addが拾うべきか」というルールです。ファイルがいったんインデックスに入れば、gitは明示的に追跡解除するまで内容の変更を追い続けます。後から.gitignoreを編集しても、追跡済みファイルには何も変わりません。「.envをコミット、青ざめる、.env.gitignoreに追加、再コミット」という古典的手順がpushのたびに秘密を送り続けるのは、このためです。

これが全員を刺すのは、gitがほぼ万能だからです。Stack Overflow 2022調査では、プロの開発者の93%超がgitを使っています(survey.stackoverflow.co)。その全員が、遅かれ早かれ先週コミットしたファイルへのルールを書くはめになるのです。

この記事の残りは少数派のケースを扱います。ルール順序のミス、否定の罠、フォルダのエッジケース、そしてIDEの疑問。ただし先に次のセクションの健全性チェックを実行してください。10回のうち9回以上、そこで調査は終了します。

どのgitignoreルールがファイルにマッチしているか調べるには?

git check-ignoreが診断ツールで、その沈黙こそが診断結果です:

# ルールが適用される場合、マッチしたルール+ファイル+行番号を表示
git check-ignore -v debug.log
# .gitignore:3:*.log    debug.log

# ルールが適用されない場合は何も表示されない——ファイルが追跡済み(またはルールが存在しない)
git check-ignore -v src/.env
# (沈黙=何を書いても、.gitignoreはこのパスを無視していない)

# 終了コード:0=無視されている、1=無視されていない——スクリプト化可能
git check-ignore -q debug.log && echo "ignored" || echo "tracked or unruly"

-v出力の読み方。無視のソース(.gitignore.git/info/exclude、またはグローバル無視ファイル)、続いて行番号:パターン、最後にパス。後のルールに驚かされたら、優先順位を思い出してください。最後にマッチしたルールが勝ちます*.logの後の!important.logは、あの1ファイルだけを再包含します。

コミット済みファイルにgitignoreが効かないのはなぜ?

ファイルを追跡解除し、ディスクには残し、削除をコミットします:

# 1ファイルを追跡解除(ローカルのコピーは残る——--cachedはインデックスだけを操作する)
git rm --cached .env
git commit -m "stop tracking .env"

# 無視ルールが効くようになったか検証する
git check-ignore -v .env

このコミット以降、パスの所有者は.gitignoreです。そこへの編集はgit statusに現れなくなり、git add .も二度と拾いません。ただしファイルは履歴には残ったままです。秘密だったなら、最新コミットからの削除では足りません。認証情報のローテーションだけが本当の修正で、履歴の書き換えは化粧です(そしてundoing the last commitが効くのは、悪いコミットがまだ先端にいる間だけです)。

過去にコミットされたゴミだらけのリポジトリ——ビルド出力、エディタの落とし物、早期に潜入したnode_modules——には、一括追跡解除の2行です:

git rm -r --cached .
git add .
git commit -m "apply .gitignore to tracked files"

これは現在のルールに照らしてインデックスを組み直します。無視対象のパスは落ち、それ以外はそのまま再追加されます。diffは派手に見えます(何千もの削除)が、ディスクからは何も消しません。追跡解除ではなくファイル自体を消したいなら、それはgit clean -fdxの領分です。git remove untracked files, safelyを参照。

gitは見たことの無いファイルしか無視しません。インデックスにいるファイルは.gitignoreに対して免疫を持っています——どんなルールを書いても、見たことを忘れさせることはできないのです。

フォルダに対してgitignoreが効かないのはなぜ?

フォルダ固有の罠が3つ:

1. 末尾スラッシュはマッチではなく意図に関わる。 buildbuild/もディレクトリにマッチしますが、build/は「ディレクトリだけを意味している」と明文化します。buildという名前のファイルはこれをすり抜けます。ただし対称性は再包含で崩れます(次の罠)。

2. 否定は除外済みディレクトリ内のファイルを救えない。 gitのドキュメントは明解です。「ファイルの親ディレクトリが除外されている場合、そのファイルを再包含することは不可能」git-scm.com/docs/gitignore)。これは性能上の決定です。gitは除外済みディレクトリを、中身を歩かず丸ごとスキップします。したがってこれは動きません

build/
!build/keep.me        # 死んだルール——gitはbuild/の中を見ない

直し方は、ディレクトリではなく中身を除外すること:

build/*
!build/keep.me        # これなら効く——build/自体は調べられるので

3. ネストした.gitignoreは自分の管轄で勝つ。 subdir/.gitignore内のルールは、subdir配下のパスについてはルートのファイルに優先します。git check-ignore -vが予想外の無視ソースを名指してきたとき、たいていこれが理由です。

VS Codeでgitignoreが効かないのはなぜ?

ほぼ例外なく、VS Codeは無実です。エディタのソース管理ビューはgitと同じインデックスを読んでいるので、症状は同一。ファイルはすでにコミット済みで、IDEを何回再起動してもインデックスは変わりません。知っておく価値のある、VS Code周りの現実が2つ:

  • エクスプローラーでグレー=無視対象、オレンジ/黄色=変更ありの追跡済み。 無視したあとに変更ありとして表示されるファイルは、追跡済みの確定情報です。上記のgit rm --cachedの修正を実行しましょう。
  • エクスプローラーの変更リストに現れないのは、ルールが効いている証拠です。未追跡ファイルとしてそもそも姿を現しません。「VS Codeがgitignoreを無視する」という報告は、CLIのgit statusと古くなったSCMビューの食い違いであることがよくあります。gitを責める前にウィンドウを再読み込みしましょう(Cmd/Ctrl+Shift+P →「Reload Window」)。

.gitignore vs .git/info/exclude vs グローバル:どれをいつ使うか

ファイルスコープコミットされる?用途
.gitignore(リポジトリ)クローンした全員Yesビルド出力、依存関係、.env——共有ルール
.git/info/exclude自分のクローンのみNo個人のゴミ:.scratch/、エディタの落とし物
core.excludesFile(グローバル)自分の全リポジトリNoOSのジャンク:.DS_StoreThumbs.db*.swp
.gitignore+否定リポジトリYes追跡済み設定の例外の再包含

グローバルファイルは、ほとんどの開発者が設定しないのに、設定すべきものです:

git config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\nThumbs.db\n*.swp\n' >> ~/.gitignore_global

盗んでいい家訓があります。ルールがチーム全員の得になるならリポジトリへ。自分だけの得ならexcludeかグローバルファイルへ。 個人的な無視ルールをコミットするからこそ、.gitignoreは300行に達し、どちらの半分がまだ生きているのか誰も分からなくなるのです。

追跡済みファイルの変更を無視するには?

追跡済みのファイル(設定テンプレートやIDEの設定ファイル)を残したい一方で、ローカルの編集がgit statusに出るのを止めたいことがあります。git update-indexの2つのフラグ。どちらもチームのワークフローに入るものではありません:

git update-index --skip-worktree config/local.dev   # ローカルの編集が静かになる
git update-index --no-skip-worktree config/local.dev  # ……そして元に戻す

擁護できるのは--skip-worktreeの方です。「ローカル版は意図的に分岐している」という宣言になります。親戚の--assume-unchangedは性能上の約束(「このファイルは変わらない」)であって、無視の仕組みではなく、gitが黙って破ることがあります。どちらのフラグも、上流が同じファイルを変更していた場合はpull時に大音量で失敗します。長持ちする答えは、作成時点からexclude経由でローカル専用設定にするか、gitが追跡して自分がコピーするテンプレートファイル(config.example)の形です。

30秒のgitignore健全性チェック

git check-ignore -v <path>        # どのルール?(沈黙=追跡済み、ルールなし)
git ls-files --error-unmatch <path>  # そもそも追跡されているか?
git rm --cached <path>            # 追跡解除、ディスクには残す
git commit -m "stop tracking <path>"
git check-ignore -v <path>        # ルールが表示されるようになる

診断、追跡解除、検証。「gitignore not working」報告の裏側は、いつも同じファイルが2つの帽子を被っている構図です。インデックスの片側では追跡され、反対側では無視される。--cachedフラグ1つで、2つ目の帽子が脱げます。

FAQ

なぜ.gitignoreが効かないのか?

ほとんどの場合、ファイルがすでに追跡済みです。gitは未追跡ファイルしか無視しません。インデックスに入ったファイルは、git rm --cachedで追跡解除してコミットするまで.gitignoreの効き目を受けません。

どのgitignoreルールがファイルにマッチしているか確認するには?

git check-ignore -v <path>を実行します。該当する.gitignoreの行とルール番号を表示します。ファイルが追跡済みで適用ルールが無い場合は、何も表示せずに終了します。

git rm --cachedでローカルファイルは削除されるのか?

いいえ。--cachedはファイルをインデックスから除去するだけで、ディスク上のコピーは残ります。削除をコミットするとファイルは未追跡になり、以降は.gitignoreが適用されます。

無視したフォルダ内のファイルをgitignoreで再包含できないのはなぜ?

gitは性能のため除外ディレクトリを丸ごとスキップします。gitドキュメントによれば、ファイルの親ディレクトリが除外されている場合、そのファイルを再包含することは不可能です。

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

OllamaがGPUを使わない?Linux・Windows・WSLでの直し方

記事を楽しんでいただけましたか?私の本業はこのような構築です。 採用のご相談