「.gitignoreにconfig.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 add/git commitでtrackedになったファイルは、.gitignoreのルールに該当しても追跡対象から外れません。「追跡を始めるかどうか」のゲートなので、既に入ってしまった後は効かない、という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つの原因パターン早見表
ポイント:圧倒的多数(体感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 --cachedをpushすると、他メンバーのローカルからもそのファイルが消えます(deletedとしてpullされる)。.env.example等のテンプレを用意し、READMEに「初回セットアップで.envを再生成する」手順を書いておくと事故が減ります。詳しくは管理からファイルを外す方法を参照。
履歴に残っている機密情報
警告:機密情報(APIキー・パスワード)が既にpushされている場合、rm --cachedしても過去の履歴には残ります。rotate(無効化/再発行)を最優先で実施し、必要ならgit filter-repoで履歴から完全削除しましょう。詳細は履歴に含まれる機密情報を完全に削除する方法を参照。
原因②:パターン文法のミス
パターンの書き方が間違っていて、そもそも一致していないケース。git check-ignore -vで何も出なければこれです。よくある文法ミスを整理しましょう。
# 誤: コメントや末尾空白で判定ズレ *.log # ← 末尾空白があるとマッチしない # 正: 余計な空白なしで書く *.log # 誤: 絶対パス風の指定(sub/以下のmatchは期待通りでないことも) /build # ルート直下のbuildのみ # 正: 全階層のbuildを除外したいなら **/build/ # または build/ # 誤: ファイルと誤解される dist # ファイル名 dist か dir dist かあいまい # 正: ディレクトリは末尾 / を付ける dist/ # 誤: 再帰表記が効かない環境 **/node_modules # 末尾 / なし # 正: 明確に **/node_modules/
globパターン文法一覧
文法チェックのコツ
- 末尾の
/:ディレクトリ限定にしたい時 - 先頭の
/:リポジトリルートからの絶対パス扱い **:複数階層のワイルドカード(**/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設定(優先順位順)
- コマンドラインのpathspec(一時的な除外)
- プロジェクトの各階層の
.gitignore(深い階層が優先) .git/info/exclude(ローカル限定、共有されない)- グローバル
~/.gitignore_global(core.excludesfile) - 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・空白の罠
エディタ設定によって.gitignoreにCRLF改行や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を全部消す(作業ツリーは残る) 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で完了させましょう。
よくある質問
/、階層を見直しましょう。**再帰表記や、ルート相対/pathとの違いに注意。!が効かないlogs/で丸ごと除外後は!logs/keep.txtは効きません。logs/*+!logs/keep.txtのように書き換えましょう。git diff --cachedで変更内容を必ず確認してください。~/.gitignore_global)またはローカル除外(.git/info/exclude)へ。リポジトリ内の.gitignoreはチーム全員に影響する共有ファイルです。git check-ignoreで実際のGit判定を確認するのが確実。関連記事
- 【Git】管理からファイルを外す方法 — rm –cachedによる追跡解除の詳細
- 【Git】untracked filesの解消方法 — .gitignore以外の整理手法
- 【Git】履歴に含まれる機密情報を完全に削除する方法 — 機密誤コミット時の完全除去
- 【Git】消したファイルを戻す方法 — 誤って消した場合の復元
- 【Git】addしたファイルの変更を確認する方法 — staged内容の検査
- 【Git】addの取り消し方法 — ステージ解除
- 【Git】pushを取り消す方法 — 機密push後の緊急対応
- 【Git】よく使うgitコマンドまとめ — 日常コマンドの早見表
まとめ
- .gitignoreは「新規追跡を防ぐフィルター」で既追跡には効かない
- 原因診断は
git check-ignore -v --allとgit ls-filesで開始 - 6パターン:既追跡/文法ミス/否定順序/親階層/優先順位/改行コード
- 最頻出は既追跡——
git rm --cachedで解除してからcommit - ディレクトリ除外と配下救済は
dir/*+!dir/keepで両立 - エンコーディング問題はエディタ設定でLF/BOMなしに統一
- 予防:プロジェクト初期に
gibo等でテンプレート生成+pre-commit hookで検出
.gitignoreが効かないと感じたら、まずgit check-ignore -vで何が起きているかを正確に把握するのが最短ルートです。そこから「既追跡か文法か優先順位か」を特定し、対応策を選べば迷いなく解決できます。機密情報の混入を避けるためにも、プロジェクト初期の.gitignore整備を習慣化してトラブルを未然に防ぎましょう。

