【Git】.gitignoreが効かない原因と解決方法|6パターン診断・check-ignore徹底活用ガイド

【Git】.gitignoreに追加しても既存ファイルが無視されないときの解決方法 Git

.gitignoreconfig.local.jsonを追加したのに、git statusには変更として出てくる」——Git初心者から中級者までよくハマる現象です。原因は大きく分けて2種類:既に追跡対象になっているか、パターン文法や優先順位の誤りか。前者はgit rm --cachedで即解決、後者はgit check-ignore -vで診断→パターン修正と進めます。

この記事では.gitignoreが効かない時の6つの原因パターン体系的な診断フローを解説します。実務で遭遇するほぼ全てのケースが網羅できる内容にまとめました。

この記事で学べること

  • .gitignoreの仕組みと「既追跡ファイルに効かない」理由
  • git check-ignore -vによる原因診断
  • 6パターンの原因と対処(既追跡/文法ミス/否定順序/親階層/優先順位/改行コード)
  • git rm --cachedによる追跡解除の手順
  • ローカル除外(.git/info/exclude)/グローバル/プロジェクトの優先順位
  • プロジェクト初期にテンプレートから.gitignoreを作る方法
  • チーム運用でignore事故を防ぐ仕組み
スポンサーリンク

なぜ既存ファイルには.gitignoreが効かないのか

Gitの.gitignore「これから追跡候補になるファイル」を自動追跡しないためのフィルターです。一度git addgit commitでtrackedになったファイルは、.gitignoreのルールに該当しても追跡対象から外れません。「追跡を始めるかどうか」のゲートなので、既に入ってしまった後は効かない、というGitの設計です。

Gitの判断順序
# 1. 変更ファイルをスキャン
# 2. .gitignore に該当するか判定
#    - tracked(index にある)→ ignore しない(変更として表示)
#    - untracked → ignore する(表示しない)

# 確認コマンド
git ls-files | grep config.local.json   # tracked なら出力あり
git check-ignore -v config.local.json   # どのルールでマッチするか

ポイント:「ignoreしたい」と思ったら2段階が必要。①追跡解除(git rm --cached)②.gitignoreでルール追加。新規ファイルなら②だけでOK、既存ファイルなら①+②。この区別を押さえれば迷いません。

STEP 0:原因を診断する

解決に進む前にgit check-ignore -vで「なぜignoreされない/される」を正確に把握します。これは.gitignore周りのトラブル解決で最強のコマンドです。

診断コマンド
# このファイルがignoreされるか確認
git check-ignore -v config.local.json
# 出力例: .gitignore:5:*.json    config.local.json
# → .gitignoreの5行目のパターン "*.json" にマッチ

# 何も出ない → ignore対象ではない(パターンが効いていない)

# tracked かどうか確認
git ls-files --error-unmatch config.local.json 2>/dev/null && echo "tracked" || echo "untracked"

# 全ての適用ルールを確認(複数あれば)
git check-ignore -v --all config.local.json

# untracked+ignored も含めた全体像
git status --ignored

# どのファイルがignoreされているかプロジェクト全体で
git ls-files --others --ignored --exclude-standard

診断結果の読み方

  • check-ignoreが出力あり+ファイルがtracked → 既追跡問題
  • check-ignoreが出力なし → パターン文法問題
  • 意図しないパターンがマッチ → 優先順位問題
  • 親階層のルールが先に該当 → 否定順序問題

6つの原因パターン早見表

原因 現象 対処
① 既に追跡されている trackedのまま変更として表示 git rm --cached
② パターン文法ミス check-ignoreがヒットしない globや末尾/を見直し
③ 否定ルール!の順序 除外したいのに再び無視される 順序入れ替え/親除外を解除
④ 親ディレクトリを先に無視 子を!で救っても戻せない 親をdir/→個別指定にする
⑤ 複数.gitignoreの優先順位 意図しないルールが当たる スコープを意識して書く位置を調整
⑥ 改行コード/BOM/空白 Windows→Git Bashで崩れる等 LFに統一/BOMなしで保存

ポイント:圧倒的多数(体感9割)は①既追跡が原因です。まずgit ls-files | grep ファイル名でtrackedかを確認、trackedならgit rm --cachedで解決。その他は文法やスコープに踏み込んだ調整が必要になります。

原因①:既に追跡されている(最頻出)

新規に.gitignoreへ追記しても、既にindexに入っているファイルはignoreされません。追跡を解除してからcommitすることで.gitignoreが有効化されます。

既追跡ファイルを外す
# .gitignoreに対象を追加(未追加なら)
echo "config/secrets.env" >> .gitignore

# indexから外す(ファイルは作業ツリーに残る)
git rm --cached config/secrets.env

# ディレクトリなら -r
git rm -r --cached node_modules/

# globで一括
git rm --cached "*.log"

# 追跡解除+.gitignoreを1コミットにまとめる
git add .gitignore
git commit -m "chore: 機密ファイル・ビルド成果物を追跡対象から除外"

# push
git push

注意:git rm --cachedpushすると、他メンバーのローカルからもそのファイルが消えます(deletedとしてpullされる)。.env.example等のテンプレを用意し、READMEに「初回セットアップで.envを再生成する」手順を書いておくと事故が減ります。詳しくは管理からファイルを外す方法を参照。

履歴に残っている機密情報

警告:機密情報(APIキー・パスワード)が既にpushされている場合、rm --cachedしても過去の履歴には残ります。rotate(無効化/再発行)を最優先で実施し、必要ならgit filter-repoで履歴から完全削除しましょう。詳細は履歴に含まれる機密情報を完全に削除する方法を参照。

原因②:パターン文法のミス

パターンの書き方が間違っていて、そもそも一致していないケース。git check-ignore -vで何も出なければこれです。よくある文法ミスを整理しましょう。

正しい .gitignore パターン
# 誤: コメントや末尾空白で判定ズレ
*.log              # ← 末尾空白があるとマッチしない

# 正: 余計な空白なしで書く
*.log

# 誤: 絶対パス風の指定(sub/以下のmatchは期待通りでないことも)
/build             # ルート直下のbuildのみ

# 正: 全階層のbuildを除外したいなら
**/build/
# または
build/

# 誤: ファイルと誤解される
dist               # ファイル名 dist か dir dist かあいまい

# 正: ディレクトリは末尾 / を付ける
dist/

# 誤: 再帰表記が効かない環境
**/node_modules    # 末尾 / なし

# 正: 明確に
**/node_modules/

globパターン文法一覧

パターン 意味 マッチ例
*.log 拡張子一致(どの階層でも) debug.log, src/app.log
/build ルート直下のみ /build(src/buildはマッチせず)
build/ ディレクトリ(どの階層でも) build/, src/build/
**/node_modules/ 明示的再帰 packages/x/node_modules/
!important.log 除外解除(否定) important.logだけ追跡
?.txt 任意1文字 a.txt, 1.txt
[abc].txt 集合から1文字 a.txt, b.txt, c.txt

文法チェックのコツ

  • 末尾の/:ディレクトリ限定にしたい時
  • 先頭の/:リポジトリルートからの絶対パス扱い
  • **:複数階層のワイルドカード(**/name=任意の階層のname)
  • コメント#で始まる行。末尾コメントは書けない
  • 空行:無視されるのでグループ分けに使える

原因③:否定ルール!の順序

.gitignoreのルールは上から下へ評価され、後に書かれたルールが勝ちます。!(否定)で例外指定するときは除外ルールよりも後に書く必要があります。

否定ルールの正しい順序
# 誤: 順序が逆で!が効かない
!important.log
*.log
# → *.log が後勝ち。important.log も無視される

# 正: 除外ルールの後に例外を書く
*.log
!important.log
# → important.log だけ追跡

# ディレクトリ配下をignoreしつつ特定ファイルだけ追跡
logs/
!logs/.gitkeep     # ← これは効かない場合がある(後述)

落とし穴:logs/のようにディレクトリ全体を除外した場合、配下のファイルを!logs/file.txtで救うことはできません。ディレクトリを除外すると配下全てがスキャンされなくなるためです。特定ファイルだけ残したいなら、次の「原因④」パターンで対処します。

原因④:親ディレクトリを先に無視してしまう

親ディレクトリを/付きで除外すると、配下のファイルは!で救えません。子ファイルを救いたいなら親はdir/*のように書くのが定石です。

配下の一部だけ残す書き方
# 誤: logs/ 全体を除外したあとは !logs/keep.txt が効かない
logs/
!logs/keep.txt

# 正: 親を「中身だけ無視」扱いに変える
logs/*
!logs/.gitkeep
!logs/README.md
# → logs/ ディレクトリ内のファイルは無視、指定ファイルだけ追跡

# サブディレクトリも再帰的に制御したいなら
logs/**/*
!logs/**/.gitkeep

ディレクトリ除外の3段階

  • dir/:ディレクトリを丸ごと除外(配下の救済不可)
  • dir/*:ディレクトリ中身だけ除外(個別救済可)
  • dir/**:ディレクトリと再帰的な全配下を除外

原因⑤:複数の.gitignoreの優先順位

Gitは複数箇所の.gitignore/除外設定を特定の順序で評価します。意図しないルールが当たっているなら、どこのファイルが効いているかを見極めます。

Gitが見るignore設定(優先順位順)

  1. コマンドラインのpathspec(一時的な除外)
  2. プロジェクトの各階層の.gitignore(深い階層が優先)
  3. .git/info/exclude(ローカル限定、共有されない)
  4. グローバル~/.gitignore_globalcore.excludesfile
  5. Git組み込みルール.git/など)
優先順位の確認
# どのルールが勝っているか
git check-ignore -v --all config.local.json
# → 複数のルールがあれば全て表示

# 各ルール設定の在り処
find . -name ".gitignore"
cat .git/info/exclude
git config --get core.excludesfile
cat "$(git config --get core.excludesfile)"

ポイント:プロジェクト固有の.gitignoreは「チームで共有したいルール」を書く場所。ローカルでだけ無視したいなら.git/info/exclude、自分のすべてのリポで無視したいならグローバル~/.gitignore_global。適切なスコープを選べば意図しない共有/非共有を防げます。

原因⑥:改行コード・BOM・空白の罠

エディタ設定によって.gitignoreCRLF改行BOMが混入すると、先頭行のルールが効かない/特定行が無視されない、といった現象が起きます。

エンコーディング問題の検出
# BOMの有無を確認(BOMがあると3バイトEF BB BFが先頭に)
xxd .gitignore | head -1

# 改行コードを確認(LF=$, CRLF=^M$)
cat -A .gitignore | head -5

# CRLF→LFに変換
dos2unix .gitignore
# または
sed -i 's/\r$//' .gitignore

# BOMを除去
sed -i '1s/^\xEF\xBB\xBF//' .gitignore

# 末尾空白を除去
sed -i 's/[[:space:]]*$//' .gitignore

予防策

  • .editorconfigでend_of_line = lfを指定
  • .gitattributesで.gitignore text eol=lfを設定
  • VS Codeは「File > Preferences > Settings」でfiles.eol = \n
  • VimやJetBrainsのエディタも既定をLFに

ルール整備後の一括再index化

.gitignoreを大幅に書き換えた後、既追跡のまま残っているファイルを一気に整理したい場合はgit rm -r --cached .git add .でindexを再構築できます。

再indexでignore一括適用
# 現在のindexを全部消す(作業ツリーは残る)
git rm -r --cached .

# 再度add(新しい.gitignoreに従って追加される)
git add .

# 変更内容を確認
git status
# → 該当ファイルがdeletedとして表示される(.gitignoreに該当したもの)

# コミット
git commit -m "chore: .gitignoreを適用してindexを再構築"

注意:この操作で改行コード変更・ファイルモード変更が大量diffとして出ることがあります(Windows/Linux混在環境など)。本来意図した「ignoreされるべきファイルだけ」のdiffになっているかcommit前に必ず確認しましょう。

再発防止:プロジェクト初期に.gitignoreを整備

テンプレートから生成
# GitHubの公式テンプレート集
# https://github.com/github/gitignore

# gibo(git ignore boilerplate)ツール
brew install gibo
gibo dump Node macOS VisualStudioCode > .gitignore

# コマンドラインでテンプレート取得
curl -sL https://www.toptal.com/developers/gitignore/api/node,macos > .gitignore

# 新規プロジェクト時の推奨フロー
git init
gibo dump Node > .gitignore
# 必要なパターンを追加
git add .gitignore
git commit -m "chore: initialize .gitignore"

チーム運用のベストプラクティス

  • プロジェクトテンプレートに.gitignoreを含める
  • 個人環境ファイル(IDE設定・OS固有)はグローバルに記載
  • ローカル限定は.git/info/excludeを活用(リポに含まれない)
  • pre-commit hookで機密ファイル(.env等)の混入を検出
  • CIで追跡してはいけないパターンを検査

実践シナリオ

シナリオ① .envを追跡解除したい

最頻出パターン
# 状況: .env をうっかりcommitしてしまった
echo ".env" >> .gitignore
git rm --cached .env
git add .gitignore
git commit -m "chore: .envを追跡対象から除外"

# 重要: pushされていた場合は機密情報rotateも忘れずに

シナリオ② node_modulesを追跡していた

ビルド成果物の除外
echo "node_modules/" >> .gitignore
git rm -r --cached node_modules/
git add .gitignore
git commit -m "chore: node_modulesを追跡対象から除外"
git push

# チームに通知:pull後、再インストール必要
# 他メンバーが実行: npm install

シナリオ③ logs/配下を除外するが.gitkeepは残したい

ディレクトリ構造保持
# .gitignore
logs/*
!logs/.gitkeep

# 確認
git check-ignore -v logs/debug.log
# → .gitignore:X:logs/* logs/debug.log

git check-ignore -v logs/.gitkeep
# → 何も出ない(追跡対象)

シナリオ④ .gitignoreを書き換えたがなぜか効かない

診断→対処
# どのルールが効いているか確認
git check-ignore -v config.local.json

# ケースA: 何も出ない → パターン文法修正
# ケースB: 出力あり+tracked → rm --cached
# ケースC: 意図しないルール → 優先順位調整

# 行数を覚えておくと便利
grep -n "config.local" .gitignore

やってはいけない落とし穴

「.gitignoreに書いたから大丈夫」と機密ファイルを作成する

.gitignoreはあくまで「自動追加を防ぐ」フィルター。人間が明示的にgit add secret.envすると追加されます。機密情報はファイル名/内容に注意し、.env.exampleに空テンプレートを置くなどの運用で安全性を担保しましょう。

git rm –cachedを知らずに.gitignoreだけ更新

既追跡ファイルには.gitignoreが効きません。追跡解除せず.gitignoreだけ変更すると「無視されない」と悩むのが王道パターン。2段階セット(rm –cached+.gitignore)で運用しましょう。

ディレクトリ除外+個別救済が動かないと混乱

logs/で丸ごと除外すると配下は!で救えません。logs/*!logs/.gitkeepのような書き方に切り替える必要があります。「ディレクトリ全体」と「ディレクトリ中身」の違いを意識しましょう。

.gitignoreをWindowsメモ帳で保存してBOM混入

Windowsの標準メモ帳で保存するとUTF-8 BOM・CRLFが混入し、Gitが正しくパターンを解釈できないケースがあります。VS Code・Vim・Notepad++などBOMなしLFで保存できるエディタを使いましょう。

rm –cached後のdeleted変更を「手違い」と思い慌てて戻す

rm --cached後、git statusでは対象ファイルが「deleted」として表示されます。これはリポジトリから削除という意味で、作業ツリーにはファイルは残っています。慌てずcommit→pushで完了させましょう。

よくある質問

Qgit check-ignore が何も表示しない
Aそのファイルは.gitignoreに一致していません。パターンの文法、末尾の/、階層を見直しましょう。**再帰表記や、ルート相対/pathとの違いに注意。
Qgit rm –cached するとファイルが消える?
A作業ツリー(ローカルの実ファイル)は残ります。indexから削除するだけなので、作業は継続可能。commit/pushすると他メンバーのローカルからは消えますが、それが意図です。
Q否定!が効かない
A親ディレクトリが先にignoreされている可能性。logs/で丸ごと除外後は!logs/keep.txtは効きません。logs/*!logs/keep.txtのように書き換えましょう。
Qグローバル.gitignoreと個別.gitignoreの優先順位は?
Aプロジェクトの.gitignoreが優先されます。グローバルは「個人環境固有」を書く場所。プロジェクト内で不要に除外されているなら、グローバルではなく個別.gitignoreを疑いましょう。
Q全追跡ファイルを再評価する rm -r –cached . は危険?
Aindexを全部作り直す操作で、大量のdiffが発生することがあります。eol変更・実行権限変更なども含まれやすいので、commit前にgit diff --cachedで変更内容を必ず確認してください。
Qチーム共有した.gitignoreに個人設定を書きたい
A書かないほうが良いです。個人環境固有はグローバル~/.gitignore_global)またはローカル除外.git/info/exclude)へ。リポジトリ内の.gitignoreはチーム全員に影響する共有ファイルです。
Q.gitignoreを変更してもIDEが認識しない
AIDE(VS Code等)によってはキャッシュを持っていることがあります。エディタを再読み込み(Command Palette→Reload Window)、またはGit拡張機能の再起動で認識されます。git check-ignoreで実際のGit判定を確認するのが確実。

関連記事

まとめ

  • .gitignoreは「新規追跡を防ぐフィルター」で既追跡には効かない
  • 原因診断はgit check-ignore -v --allgit ls-filesで開始
  • 6パターン:既追跡/文法ミス/否定順序/親階層/優先順位/改行コード
  • 最頻出は既追跡——git rm --cachedで解除してからcommit
  • ディレクトリ除外と配下救済はdir/*!dir/keepで両立
  • エンコーディング問題はエディタ設定でLF/BOMなしに統一
  • 予防:プロジェクト初期にgibo等でテンプレート生成+pre-commit hookで検出

.gitignoreが効かないと感じたら、まずgit check-ignore -vで何が起きているかを正確に把握するのが最短ルートです。そこから「既追跡か文法か優先順位か」を特定し、対応策を選べば迷いなく解決できます。機密情報の混入を避けるためにも、プロジェクト初期の.gitignore整備を習慣化してトラブルを未然に防ぎましょう。