.gitignoreが効かない原因は“追跡中”|git rm と –cached の正しい使い分け

デプロイ/バージョン管理

.gitignore に書いたのに、なぜか無視されない…。」

ログやビルド成果物のようなディレクトリで一度はぶつかる定番の悩みです。原因のほとんどはシンプルで、そのファイル(やフォルダ)がすでに Git の“追跡対象”になっていること。.gitignore は「これから追跡しない」ための仕組みなので、いったん追跡から外す手順が必要です。

ここで迷いやすいのが git rmgit rm --cached の違い

  • git rm追跡から外す+物理削除(ローカルからも消える)
  • git rm --cached追跡から外すだけ(ローカルには残る)

ログやキャッシュのようにローカルには残したいものは --cached を使うのが基本です。

この記事では、.gitignore が効かないときの安全で再現性の高い直し方を、チェックリストと実例でコンパクトにまとめます。先に正しい ignore パターンを記述し、git rm -r --cached → コミット → 検証までを一気通貫で解説。git check-ignore -v を使った確認方法や、.gitkeep だけ例外的に残す書き方、チーム運用での注意点も取り上げます。

この記事でわかること

  • .gitignore が効かない根本原因と考え方
  • git rm / git rm --cached の使い分け(失敗しない判断基準)
  • 直し方の最短手順(パターン記述 → 追跡解除 → 確認 → コミット)
  • ありがちミス(パスの基準、//**、否定パターン ! など)の回避策

※機密ファイルをコミットしてしまった場合は、--cached だけでなく履歴からの除去(filter-repo / BFG 等)が必要です。本記事ではまず日常運用での“効かない問題”解消にフォーカスします。

結論(TL;DR)

  1. 先に .gitignore に正しいパターンを書く
  2. 追跡解除(物理は残す):
    git rm -r --cached <対象パス>
    git add .gitignore
    git commit -m "chore: stop tracking and ignore <対象パス>"
  3. git statusgit check-ignore -v効いていることを確認

ポイント.gitignore の修正より先に git rm --cached を実行すると、後の git add でまた拾ってしまうことがあるため、必ず「ルール記述→追跡解除」の順に。

.gitignore が効かない根本原因

  • .gitignore未追跡(untracked) のファイルにのみ効果があります。
  • 既にコミット済み or 追加済み(tracked) のものには影響しません
  • つまり、index(追跡リスト)から外すgit rm --cached が必要。

git rm と git rm --cached の違い(ここが超重要)

結論だけ先に

  • git rm <path>追跡から外す+物理ファイルも削除(作業ツリーから消える)
  • git rm --cached <path>追跡から外すだけ(物理ファイルは残る)

どちらを使う?

  • ログ/ビルド/キャッシュなど「ローカルには残したい」もの → --cached が基本
  • 本当に消したいファイル(誤コミットした鍵など) → git rm(物理削除)
    • ※機密情報は履歴からの完全除去git filter-repo / BFG Repo-Cleaner)も検討
観点git rmgit rm --cached
追跡状態外す外す
物理ファイル削除する残す
典型用途本当に消したいものログ・ビルド・キャッシュ
チーム影響pullで消えるpullで追跡が外れるだけ

最短レシピ:.gitignore → 追跡解除 → 確認 → コミット

1) .gitignore に正しいルールを書く

例:tmp/cache/logs/v3.0/ 以下をすべて無視する

# v3.0 配下は全部無視
tmp/cache/logs/v3.0/**

ルールの基礎

先頭 / … リポジトリルートからの絶対指定
末尾 /ディレクトリ限定
**任意の階層にマッチ
否定 !例外(後述)

2) 追跡解除(物理ファイルは残す)

git rm -r --cached tmp/cache/logs/v3.0
  • 変更が多くて止められる場合は -f を付けることもあります(要注意)。

3) 確認

git status
git check-ignore -v tmp/cache/logs/v3.0/some.log   # どのルールで無視されたかが出る

4) コミット

git add .gitignore
git commit -m "chore: stop tracking tmp/cache/logs/v3.0 and ignore it"

実例:tmp/cache/logs/v3.0/ を“全部無視”、.gitkeep だけ追跡

.gitkeep を残すことで空ディレクトリ構造を共有したい、という実務はよくあります。

# v3.0 配下は全部無視
tmp/cache/logs/v3.0/**

# ただし .gitkeep は追跡する
!tmp/cache/logs/v3.0/.gitkeep

コマンド:

git rm -r --cached tmp/cache/logs/v3.0
git add .gitignore tmp/cache/logs/v3.0/.gitkeep
git commit -m "chore: ignore logs v3.0 but keep .gitkeep"

まだ効かない?「つまずきあるある」チェックリスト

  1. 順序問題(最後の一致が有効)
    • 例外 ! の行は、対象を無視する行の後に書く必要があります。
    • 悪例:先に !file、後で dir/** と書くと file も無視される。
  2. パス基準の勘違い
    • 先頭 /リポジトリルート基準。
    • 先頭 / が無いと、どの階層でもマッチする可能性があります。
    • .gitignoreサブディレクトリに置く場合、その場所基準の相対にもなる点に注意。
  3. ディレクトリ指定の / 抜け
    • logslogs/ は意味が違います。ディレクトリだけを対象にするなら末尾 / を付ける。
  4. Windows のパス区切り
    • .gitignore の区切りは / 固定。バックスラッシュ \ は使いません。
  5. 既に追跡されている
    • そもそも git rm --cached を実施していない/コミットしていない。
    • git ls-files <path> で追跡中かを確認。
  6. 除外は効いているが強制追加している
    • git add -f <file> を使うと無視ルールを強制突破します。不要なら外しましょう。
  7. 別の場所での除外設定
    • .git/info/exclude やグローバル .gitignore_global競合するルールが無いか。

任意階層にある logs ディレクトリをすべて無視

logs/

リポジトリ直下の logs/ だけ無視

/logs/

拡張子が .log のファイルを無視

*.log

深い階層も含めて logs 配下をすべて無視

logs/**

すべて無視しつつ .gitkeep は追跡する

logs/**
!logs/.gitkeep

よくあるQ&A

Q1. .gitignore を直したのに効きません。
A. 変更前に既に追跡されている可能性が高いです。git rm -r --cached <対象> → コミットまで行いましょう。

Q2. git rmgit rm --cached はどちらを使う?
A. ログ/ビルド/キャッシュなどローカルに残したいものは --cached完全に消すなら git rm。機密は履歴除去も。

Q3. 空ディレクトリを共有したい
A. .gitkeep を置いて、否定パターン ! で例外にします。

Q4. ルールが当たっているか確認したい
A. git check-ignore -v <path> を使うと、どの行でマッチしたかが見えて便利。

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

  • PRテンプレにチェック項目
    • .gitignore 変更時は git rm --cached のコミットを含めたか
    • .gitkeep など例外が必要な場合、否定ルールの順序は正しいか
  • 生成物は常に無視
    • vendor/node_modules/storage/logs/、ビルド成果物などは最初から除外
  • ルールは“疎”に保つ
    • 複雑なワイルドカードは検証を前提に(git check-ignore -v
  • 機密は即時対応
    • 誤ってコミットした秘密鍵・認証情報は、履歴ごと削除速やかに鍵をローテーション

まとめ

.gitignore が効かない原因の本質は、対象がすでに Git に「追跡済み」であることです。解決の基本線はシンプルで、まず .gitignore に正しいルールを記述し、そのうえで git rm -r --cached <対象> で追跡だけを外し、コミットして状態を確定させます。最後に git check-ignore -v <path> でどのルールに一致したかを確認すれば、再発しにくい“根拠ある直し方”になります。

また、git rm は「追跡解除+物理削除」、git rm --cached は「追跡解除のみ」という違いを理解しておくと運用が安定します。ログやビルド成果物のようにローカルには残したいものは --cached を原則に、逆に完全に消したいものは git rm を選びます。万一、機密情報をコミットしてしまった場合は、単なる追跡解除では不十分で、履歴からの除去(filter-repo/BFG 等)と秘密情報の速やかなローテーションが必要です。

日々の開発では、この手順をチームの標準にしておくと、同種のトラブルはぐっと減ります。ルールを先に書く → 追跡を外す → 動作を検証する――この流れを一度身体で覚えてしまえば、.gitignore まわりで迷う時間はほぼゼロになります。

参照リンク

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント