- Git
- 技術 💻
.gitignoreが効かない原因と直し方|check-ignoreで切り分け
.gitignoreが効かない原因の多くは、「そのファイルがすでにGitに追跡されている」ことです。 .gitignoreは「まだ追跡していないファイル」を無視する仕組みなので、一度コミットしたファイルは書き足しても無視されません。この場合は git rm --cached で追跡を外すと直ります。
ただし、原因はほかにもあります。パターンの書き方、親ディレクトリを除外したことによる ! の空振り、大文字小文字、目に見えない全角スペース、ファイルの置き場所などです。この記事では、原因ごとに実際にGitで再現し、git check-ignore -v などの出力をそのまま掲載しています(検証環境:git version 2.43.0、Linux)。「本当に効かなくなるもの」と「実は問題ないもの」も実験で区別しました。上から順に確認すれば、原因を特定できます。
.gitignoreが効かない原因の早見表
| 症状 | 主な原因 | 確認コマンド | 直し方 |
|---|---|---|---|
書いたのに git status に「modified」で出る |
すでに追跡されている | git ls-files -ci --exclude-standard |
git rm --cached <ファイル> |
| 一部の階層だけ無視されない | 先頭 /・途中の /・** の意味の取り違え |
git check-ignore -v <パス> |
パターンを直す |
! で戻したファイルが無視されたまま |
親ディレクトリごと除外している | git check-ignore -v <パス> |
dir/ を dir/* にする |
| 他の人(他のOS)の環境では効くのに自分だけ効かない | 大文字小文字の違い | git config core.ignorecase |
パターンの大文字小文字をそろえる |
| 行は正しく見えるのに効かない | 全角スペース、行頭スペース、行末コメント、UTF-16 | od -c .gitignore |
文字を消す、UTF-8で保存し直す |
| 自分の環境だけ効く/効かない | .git/info/exclude・グローバル設定 |
git check-ignore -v <パス> |
置き場所を見直す |
| 他の人の環境で無視されない | .gitignoreをコミットしていない | git status |
.gitignoreをコミットする |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「.gitignoreが効かない原因と直し方|check-ignoreで切り分け」
まず使う診断コマンド:git check-ignore -v
「なぜ無視される(されない)のか」は、git check-ignore -v で一発でわかります。 どのファイルの何行目の、どのパターンに一致したかを表示してくれます。
git check-ignore -v <調べたいパス>
表示の形式は ファイル名:行番号:パターン<TAB>パス です。何も表示されない(終了コード1)なら、どのパターンにも一致していません。
| コマンド | わかること |
|---|---|
git check-ignore -v <パス> |
一致したルールの場所と内容 |
git check-ignore -v --no-index <パス> |
追跡済みファイルでも、ルールに一致するかを確認 |
git ls-files -ci --exclude-standard |
無視ルールに一致しているのに追跡されているファイルの一覧 |
git status --ignored |
無視されているファイルの一覧 |
git config core.ignorecase |
大文字小文字を区別しない設定か |
診断フローチャート
flowchart TD
A[.gitignoreが効かない] --> B{git ls-files -ci --exclude-standard<br>に出てくる?}
B -- はい --> C[追跡済み<br>git rm --cached で外す]
B -- いいえ --> D{git check-ignore -v で<br>何か表示される?}
D -- 何も出ない --> E{パターンは合っている?<br>先頭と末尾の / や大文字小文字}
E -- 合っていない --> F[パターンを直す]
E -- 合っているはず --> G[od -c で全角スペース<br>行頭スペース 文字コードを確認]
D -- 表示される --> H{パターンが ! で始まる?}
H -- はい --> I[無視されていない状態<br>親ディレクトリ除外や順序を確認]
H -- いいえ --> J[無視されている<br>他の環境で効かないなら<br>置き場所とコミット状況を確認]
以下、原因ごとに再現していきます。
原因1:すでに追跡されている(いちばん多い)
一度 git add してコミットしたファイルは、あとから.gitignoreに書いても無視されません。 環境変数ファイル .env をうっかりコミットしてしまった状況を再現します。
$ echo ".env" > .gitignore
$ echo "SECRET=xyz" > .env # 中身を変更
$ git status --short
M .env
?? .gitignore
.gitignoreに書いたのに .env は「M(変更あり)」と表示されます。check-ignore の結果を見ると理由がわかります。
$ git check-ignore -v .env
$ git check-ignore -v --no-index .env
.gitignore:1:.env .env
$ git ls-files -ci --exclude-standard
.env
通常の check-ignore は追跡済みファイルに対して何も表示しません。 --no-index を付けると、ルール自体には一致していることがわかります。そして git ls-files -ci --exclude-standard が「無視ルールに一致しているのに追跡されているファイル」を一覧してくれます。
直し方:git rm --cached
--cached を付けると、手元のファイルは残したまま、Gitの追跡だけを外せます。
$ git rm --cached .env
rm '.env'
$ git status --short
D .env
?? .gitignore
$ git check-ignore -v .env
.gitignore:1:.env .env
D(削除)とステージされていますが、これは「リポジトリから外す」という意味で、手元の .env は残っています。.gitignoreと一緒にコミットすれば完了です。
$ git add .gitignore && git commit -m "stop tracking .env"
$ git status --short
(何も表示されない)
注意:pullした他の人の手元からはファイルが消える
git rm --cached のコミットをpullした側では、そのファイルが作業ディレクトリから削除されます。 実際に別のクローンで確かめました。
$ ls -a # pull前(別のクローン)
.
..
.env
.git
dist
main.py
$ git pull -q
$ ls -a # pull後
.
..
.git
.gitignore
main.py
.env や dist/ がなくなっています。設定ファイルなど各自の手元に必要なものは、事前にチームへ周知し、pull前にバックアップしてもらうと安心です。
一括で直す方法と、その注意点
よく紹介される一括修復の方法は次のとおりです。
git rm -r --cached .
git add .
git commit -m "apply .gitignore"
実行すると、無視対象だけが削除としてステージされます。
$ git rm -r --cached -q .
$ git add .
$ git status --short
D .env
A .gitignore
D dist/app.js
D node_modules/lib/index.js
便利ですが、すべてのファイルを一度インデックスから外して入れ直すため、改行コードの設定(.gitattributes や core.autocrlf)が途中で変わっていた場合などに、無関係なファイルまで変更扱いになることがあります。 対象を絞りたいときは、追跡中の無視対象だけを外すほうが安全です。
$ git ls-files -ci --exclude-standard -z | xargs -0 git rm --cached
rm '.env'
rm 'dist/app.js'
どちらの方法でも、コミット前に git status で「D」になっているのが意図したファイルだけか確認 しましょう。
原因2:パターンの書き方
.gitignoreのパターンは、/ の位置で意味が大きく変わります。 次のファイル構成で試しました。
build/a.o
src/build/b.o
logs/app.log
logs/2026/x.log
先頭の / は「.gitignoreと同じ階層だけ」
$ cat .gitignore
.env
/build/
logs/*.log
$ git check-ignore -v build/a.o src/build/b.o logs/app.log logs/2026/x.log
.gitignore:2:/build/ build/a.o
.gitignore:3:logs/*.log logs/app.log
/build/ はルート直下の build だけに一致し、src/build/ は対象外 でした。また logs/*.log の * は / をまたがないため、logs/2026/x.log には一致していません。
** で階層をまたぐ
$ cat .gitignore
.env
build/
logs/**/*.log
$ git check-ignore -v build/a.o src/build/b.o logs/app.log logs/2026/x.log
.gitignore:2:build/ build/a.o
.gitignore:2:build/ src/build/b.o
.gitignore:3:logs/**/*.log logs/app.log
.gitignore:3:logs/**/*.log logs/2026/x.log
先頭に / のない build/ はどの階層の build ディレクトリにも一致し、logs/**/*.log は logs 以下の全階層の .log に一致しました。
途中に / があると、.gitignoreの位置が起点になる
docs/api/tmp/t.txt を無視するつもりで api/tmp と書いてみます。
$ cat .gitignore
api/tmp
$ git check-ignore -v docs/api/tmp/t.txt
(何も表示されない:終了コード1)
途中に / を含むパターンは、先頭に / があるのと同じく「.gitignoreのある場所から」の相対パスとして扱われます。 どの階層でも一致させたいなら **/api/tmp と書きます(.gitignore:1:**/api/tmp docs/api/tmp/t.txt と一致することを確認済み)。
末尾の / は「ディレクトリだけ」
tmp という名前のファイルと、docs/api/tmp/ ディレクトリがある状態で tmp/ と書きました。
$ cat .gitignore
tmp/
$ git check-ignore -v tmp docs/api/tmp/t.txt
.gitignore:1:tmp/ docs/api/tmp/t.txt
ルート直下の tmp(ファイル)は無視されず、ディレクトリの中身だけが無視されました。 ファイルもディレクトリも無視したいなら、末尾の / を付けずに tmp と書きます。
| パターン | 一致するもの |
|---|---|
build |
どの階層でも、build という名前のファイルとディレクトリ |
build/ |
どの階層でも、build という名前のディレクトリだけ |
/build/ |
ルート直下の build ディレクトリだけ |
api/tmp |
.gitignoreから見た api/tmp だけ(途中の / で位置固定) |
**/api/tmp |
どの階層の api/tmp でも |
logs/*.log |
logs 直下の .log だけ |
logs/**/*.log |
logs 以下すべての階層の .log |
原因3:親ディレクトリを除外すると ! で戻せない
! は除外を取り消す(再び追跡対象にする)パターンですが、親ディレクトリごと除外していると効きません。 config/local/ を無視しつつ、keep.yml だけは共有したいケースです。
$ cat .gitignore
config/local/
!config/local/keep.yml
$ git check-ignore -v config/local/keep.yml
.gitignore:1:config/local/ config/local/keep.yml
$ git status --short --untracked-files=all
?? .env
keep.yml は1行目のルールで無視されたままです。 Gitはディレクトリごと除外すると、その中を見に行かないため、中のファイルに対する ! が評価されません。
ディレクトリそのものではなく「中身」を除外する書き方(dir/*)に変える と、! が効きます。
$ cat .gitignore
config/local/*
!config/local/keep.yml
$ git check-ignore -v config/local/keep.yml config/local/secret.yml
.gitignore:2:!config/local/keep.yml config/local/keep.yml
.gitignore:1:config/local/* config/local/secret.yml
$ git status --short --untracked-files=all
?? .env
?? config/local/keep.yml
ここで大切なのが、-v 付きの出力で ! から始まるパターンが表示されたら「無視されていない」という意味 だという点です。-v なしで実行すると、無視されるものだけが表示されます。
$ git check-ignore config/local/keep.yml config/local/secret.yml
config/local/secret.yml
さらに深い階層のファイルを戻すときは、途中のディレクトリも1段ずつ ! で戻す必要があります。
$ cat .gitignore
config/*
!config/local/
config/local/*
!config/local/keep.yml
$ git status --short --untracked-files=all
?? .gitignore
?? config/local/keep.yml
config/top.yml や config/local/secret.yml は無視され、keep.yml だけが追跡対象になりました。
原因4:ファイル名の大文字小文字
.gitignoreの大文字小文字の扱いは、core.ignorecase の設定で変わります。 Windows・macOSで作ったリポジトリは多くの場合 true(区別しない)、Linuxでは false(区別する)になります。Thumbs.db と書いて、実際のファイル名が thumbs.db の場合を試しました。
$ cat .gitignore
.env
Thumbs.db
$ git config core.ignorecase
(設定なし=false)
$ git check-ignore -v thumbs.db
(何も表示されない:終了コード1)
$ git -c core.ignorecase=true check-ignore -v thumbs.db
.gitignore:2:Thumbs.db thumbs.db
Linuxや、Linuxで動くCI環境では、大文字小文字が違うと無視されません。 「自分のPCでは効いているのに、CIやコンテナでは効かない」ときはここを疑います。パターンは実際のファイル名と大文字小文字までそろえる のが確実です。
原因5:目に見えない文字・文字コード
「正しく書いたはずなのに効かない」ときは、見えない文字を疑います。 debug.log を無視する1行を、いろいろな形で保存して試しました。
| .gitignoreの中身 | 結果 |
|---|---|
UTF-8(BOMあり)で debug.log |
効く |
行末に半角スペース debug.log |
効く(行末の半角スペースは無視される) |
| 改行コードCRLF | 効く |
行末に全角スペース debug.log |
効かない |
行頭に半角スペース debug.log |
効かない |
行末コメント debug.log # logs |
効かない |
| UTF-16で保存 | 効かない |
たとえば全角スペースの場合、check-ignore は何も返しません。
$ printf 'debug.log\xe3\x80\x80\n' > .gitignore # 行末に全角スペース
$ git check-ignore -v debug.log
(何も表示されない:終了コード1)
# がコメントになるのは行頭だけ で、行の途中の # はパターンの一部として扱われます。コメントは別の行に書きましょう。
見えない文字は od -c で確認できます。UTF-8のBOMは先頭の 357 273 277 として表示されます(今回の検証では、BOMがあっても問題なく効きました)。
$ head -c 12 .gitignore | od -c | head -2
0000000 357 273 277 d e b u g . l o g
0000014
UTF-16は、Windows PowerShell 5.1で echo "debug.log" > .gitignore のようにリダイレクトして作ると、既定でその形式になります。 エディタで「UTF-8」を選んで保存し直すと直ります。
原因6:置き場所(どの無視ファイルが効いているか)
無視ルールは.gitignore以外の場所にも書けます。 置き場所によって「誰に効くか」が違います。
| 置き場所 | 効く範囲 | 共有されるか |
|---|---|---|
リポジトリ直下の .gitignore |
リポジトリ全体 | される(コミットする) |
サブディレクトリの .gitignore |
そのディレクトリ以下 | される |
.git/info/exclude |
そのリポジトリの自分の環境だけ | されない |
core.excludesFile で指定したファイル |
自分の全リポジトリ | されない |
~/.config/git/ignore |
自分の全リポジトリ(core.excludesFile 未設定時) |
されない |
check-ignore -v は、どのファイルのルールが効いたかも表示してくれます(ホームディレクトリのパスは ~ に置き換えています)。
$ git check-ignore -v web/cache.tmp cache.tmp
web/.gitignore:1:*.tmp web/cache.tmp
$ git check-ignore -v scratch.txt
.git/info/exclude:7:scratch.txt scratch.txt
$ git check-ignore -v .DS_Store
~/.config/git/ignore:1:.DS_Store .DS_Store
web/.gitignore の *.tmp は、web の外にある cache.tmp には効いていません。
core.excludesFileを設定すると ~/.config/git/ignore は読まれない
見落としやすいのがこの点です。core.excludesFile を設定すると、既定の ~/.config/git/ignore は使われなくなります。
$ git config --global core.excludesFile '~/.gitignore_global'
$ git check-ignore -v .DS_Store a.swp
~/.gitignore_global:1:*.swp a.swp
さっきまで無視されていた .DS_Store が、表示されなくなりました。グローバルの無視設定は1か所にまとめる と混乱しません。
チームで共有すべきもの(ビルド成果物、依存パッケージ)はリポジトリの.gitignoreへ、個人のエディタやOSのファイルはグローバル設定へ と分けるのがおすすめです。
原因7:.gitignore自体をコミットしていない
.gitignoreも普通のファイルなので、コミットしてpushしないと他の人には届きません。 自分の環境では効いているのに他の人の環境で無視されないときは、git status で .gitignore が ??(未追跡)や M(未コミットの変更)になっていないか確認します。逆に「.gitignoreを.gitignoreに書いてしまった」場合も同じ症状になります。
秘密情報をすでにpushしてしまったら
.gitignoreに追加しても、過去のコミット履歴に残った内容は消えません。 履歴から消すには git filter-repo などで履歴を書き換え、強制pushする必要があります。あわせて、漏れたAPIキーやパスワードはすぐに無効化し、新しいものを発行 してください。履歴を消すより先にキーを無効化するのが確実な対策です。
予防のチェックリスト
| チェック | 内容 |
|---|---|
| リポジトリ作成直後に.gitignoreを置く | 最初のコミット前に入れておくと、追跡済み問題が起きない |
| 言語・フレームワーク向けのテンプレートを使う | GitHubの gitignore テンプレートなどを土台にする |
git add . の前に git status |
意図しないファイルが入っていないか確認 |
追加したら git check-ignore -v で確かめる |
書いたルールが効いているかをその場で確認 |
.env.example を共有する |
本物の .env は無視し、ひな形だけコミットする |
よくある質問
Q. .gitignoreを変更したのに git status が変わりません。キャッシュを消す必要がありますか?
A. .gitignoreの変更はすぐに反映されます。変わらない場合は、そのファイルがすでに追跡されている可能性が高いです。git ls-files -ci --exclude-standard で確認し、git rm --cached で追跡を外してください。
Q. 無視しているファイルを、一時的にコミットしたいときは?
A. git add -f <ファイル> で強制的に追加できます。ただし一度追加すると以後は追跡されるため、.gitignoreの対象でも変更が表示されるようになります。
Q. 追跡したまま、自分の変更だけGitに無視させることはできますか?
A. .gitignoreではできません。git update-index --skip-worktree <ファイル> という方法がありますが、pullなどで衝突したときの扱いがわかりにくくなります。設定ファイルなら、ひな形(config.example など)だけを追跡し、本体は.gitignoreで無視する構成にするのが扱いやすいです。
まとめ
- いちばん多い原因は「すでに追跡されている」。
git ls-files -ci --exclude-standardで確認し、git rm --cachedで外す git rm --cachedのコミットをpullした側では、そのファイルが消える ので事前に周知する- 原因の特定は
git check-ignore -v。!から始まる行が出たら「無視されていない」という意味 - 先頭
/は位置固定、末尾/はディレクトリだけ。**を使うと階層をまたげる - 親ディレクトリを除外すると
!が効かない。dir/ではなくdir/*と書く - 全角スペース・行頭スペース・行末コメント・UTF-16は効かない原因になる(BOMやCRLF、行末の半角スペースは問題なし)
core.excludesFileを設定すると~/.config/git/ignoreは読まれない
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「.gitignoreが効かない原因と直し方|check-ignoreで切り分け」
株式会社RJCでは、こうしたGitのつまずきと直し方を、プロジェクトの中で仲間と共有し合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。