.gitignore が反映されない・効かない原因と直し方(追跡済みは git rm --cached)

PR
.gitignore が反映されない・効かない原因と直し方(追跡済みは git rm --cached)
この記事は約18分で読めます。

.gitignore は、まだ追跡していないファイルにだけ効きます。すでに git add したりコミットしたりして Git が追跡している(変更を記録する対象にしている)ファイルは、.gitignore に書いても無視されません。Git の文書(gitignore と gitfaq)がそう書いています。

追跡をやめるには、git rm --cached <ファイル>(フォルダは git rm -r --cached <フォルダ>)を実行し、.gitignore と一緒にコミットします。外れるのはインデックス(索引。次のコミットの候補)からだけで、手元のファイルは残ります。

git rm --cached .env app.log
git rm -r --cached logs
git add .gitignore
git commit -m "stop tracking ignored files"

.env などは、自分のファイル名に替えます。

ただし、手元で試すと、このコミットを push したあと、ほかの人が pull すると、その人の手元から .env などが消えました(Git の文書には見つからず、試した結果です)。また、追跡をやめても、前のコミットには中身が残っていました。パスワードや API キーが入っていたなら、最初に、その鍵を使えなくして新しい鍵に替えます(.env の記事の手順)。

確かめた版は、Docker の Linux の Git 2.54.0 と、手元の Mac の Git 2.39.3(Apple Git-145)です(2026年10月23日に実行しました。最新の 2.56.0 と Windows では実行していません)。表示が版で違う所には、版を添えます。出力のパスの頭は … に省きました。コミットのハッシュは、流すたびに変わる例です。.env の中身は、本物ではないダミーの 1 行です。

この記事でわかること
  • .gitignore は、追跡していないファイルにだけ効く。追跡済みかは、git ls-files --cached --ignored --exclude-standard に出るかで分かる
  • 追跡をやめるのは git rm --cached <ファイル>(フォルダは -r)。手元のファイルは残る
  • 手元で試すと、そのコミットを pull した人の手元からはファイルが消え、前のコミットには中身が残った
  • 追跡していないのに効かないときは、git check-ignore -v に何も出ないか、親のフォルダに当たる行が出る。無視したくないのに無視されるときは、出た行の元のファイルを見る

.gitignore が反映されないのはなぜ?

すでに追跡しているファイルには効かない

Git の文書(gitignore)は、.gitignore を「わざと追跡しないファイルを、Git に無視させるもの」と説明し、「すでに Git が追跡しているファイルには影響しない」と書いています(英語の原文は "Files already tracked by Git are not affected")。.gitignore の目的は、追跡していないファイルを、追跡していないままにすることです。

Git の FAQ(gitfaq)にも「無視するよう書いたのに、まだ追跡されている」という項目があります。.gitignore に足す前からそのファイルを追跡していたから、というのが答えです。直し方は、git rm --cached <ファイルかパターン> で追跡をやめ、.gitignore にそのファイルに当たるパターンを足す、と書かれています。

確かめに使ったリポジトリでは、.env・app.log・logs/a.log・logs/b.log・main.txt を git add してコミットしてから、.gitignore を作りました。中身は次の 3 行です。.env と app.log には、そのあと 1 行ずつ足してあります。

$ cat -n .gitignore
     1	.env
     2	*.log
     3	logs/
$ git status --short
 M .env
 M app.log
?? .gitignore

.env と app.log は追跡中で、1 行足したので、変更のあるファイルとして M(M が右の列)で出ています。.gitignore に書いたのに、出続けています。?? の .gitignore は、まだ追跡していないファイルです。

追跡しているかを確かめる

追跡しているかは、次の 3 つで確かめられます。

1つ目は git ls-files --cached --ignored --exclude-standard です。追跡中のファイルのうち、.gitignore などに当たるものを一覧にします。git ls-files は、標準の除外の規則を自分では読まないので、--exclude-standard(.git/info/exclude・各フォルダの .gitignore・全体の除外ファイルを読む)を付けます。ここに出るのは、追跡しているのに、.gitignore などに当たっているファイルです。

$ git ls-files --cached --ignored --exclude-standard
.env
app.log
logs/a.log
logs/b.log

2つ目は git check-ignore -v です。このコマンドは、渡したパスが .gitignore などで無視されるかを調べ、無視されるならそのパスを出します。ただし、追跡中のファイルは、除外の規則の対象ではないので、何も出ません(終了コード〔コマンドが終わるときに返す数〕は 1 でした)。何も出ないのは「どの行にも当たらない」ときと同じ表示なので、これだけでは見分けられません。次の --no-index と並べて見ます。

$ git check-ignore -v .env app.log

3つ目は、--no-index を付けることです。インデックスを見ずに調べるので、追跡中のファイルでも、どの行に当たるかが出ます。git add . で追跡に入ってしまったのに無視されなかった理由を調べるときに使う、と文書に書かれています。付けたときと付けないときの違いで、追跡しているかが分かります。

$ git check-ignore -v --no-index .env app.log logs/a.log
.gitignore:1:.env	.env
.gitignore:2:*.log	app.log
.gitignore:3:logs/	logs/a.log

追跡しているファイルを外すには?(git rm --cached)

ファイルを外す

追跡をやめるには、git rm --cached で、インデックスから外します。Git の文書は、--cached を「インデックスからだけ消す。作業ツリー(手元で編集しているファイルのある場所)のファイルは、変えていてもいなくても、そのまま残す」と説明しています。手元では、.env に 1 行足した(git add していない)状態でも通り、ファイルは残りました。

$ git rm --cached .env app.log
rm '.env'
rm 'app.log'

git rm は、外したファイルごとに 1 行(rm コマンドの形)を出します。その後に、.gitignore へそのファイルの名前を足しておけば、あとのコミットにまた入るのを防げる、と文書にあります。

フォルダごと外す(-r)

フォルダごと外すときは -r が要ります。付けないと、次のように止まります(終了コードは 128 でした)。

$ git rm --cached logs
fatal: not removing 'logs' recursively without -r

-r を付けると、フォルダの中のファイルが 1 つずつ外れます。

$ git rm -r --cached logs
rm 'logs/a.log'
rm 'logs/b.log'

ここまでの状態を見ます。外した分は、インデックスから消えた印の D で出ます(D .env のように、D が左の列です)。ls のとおり、ファイルは手元に残っています。

$ git status --short
D  .env
D  app.log
D  logs/a.log
D  logs/b.log
?? .gitignore
$ ls .env app.log logs/a.log logs/b.log
.env
app.log
logs/a.log
logs/b.log

.gitignore を git add して、コミットします。そのあとの git status --short は空になり、--ignored を付けると、無視されているものが !! で出ます。

$ git add .gitignore
$ git commit -m "stop tracking ignored files"
[main 4655261] stop tracking ignored files
 5 files changed, 3 insertions(+), 4 deletions(-)
 delete mode 100644 .env
 create mode 100644 .gitignore
 delete mode 100644 app.log
 delete mode 100644 logs/a.log
 delete mode 100644 logs/b.log
$ git status --short
$ git status --short --ignored
!! .env
!! app.log
!! logs/

追跡をやめたあとは、.gitignore が効いています。

$ git check-ignore -v .env app.log logs/a.log
.gitignore:1:.env	.env
.gitignore:2:*.log	app.log
.gitignore:3:logs/	logs/a.log

pull した人の手元からは消える

ここからは、Git の文書には見つかっていません。手元で試した結果です。上のコミットを push してから、前に clone してあった別のリポジトリ(bob)で git pull すると、.env などが手元から消えました。

まず push です。

$ git push
To ../remote.git
   888e6a5..4655261  main -> main

bob の側の、pull の前のファイルです。

$ ls .env app.log logs/a.log logs/b.log main.txt
.env
app.log
logs/a.log
logs/b.log
main.txt

git pull です。

$ git pull
From …/remote
   888e6a5..4655261  main       -> origin/main
Updating 888e6a5..4655261
Fast-forward
 .env       | 1 -
 .gitignore | 3 +++
 app.log    | 1 -
 logs/a.log | 1 -
 logs/b.log | 1 -
 5 files changed, 3 insertions(+), 4 deletions(-)
 delete mode 100644 .env
 create mode 100644 .gitignore
 delete mode 100644 app.log
 delete mode 100644 logs/a.log
 delete mode 100644 logs/b.log

pull のあとは、.env・app.log・logs/ の中のファイルが無くなり、main.txt だけが残りました。

$ ls .env app.log logs/a.log logs/b.log main.txt
ls: .env: No such file or directory
ls: app.log: No such file or directory
ls: logs/a.log: No such file or directory
ls: logs/b.log: No such file or directory
main.txt

手元の Mac の Git 2.39.3 でも、ハッシュのほかは同じ結果でした。pull する側に手元の変更があるときは、確かめていません。pull の仕組みは git pull と git fetch の記事で説明しています。

過去のコミットには残る

追跡をやめても、前のコミットには中身が残っています。同じ bob の側で、.env の履歴を見ると、追跡をやめたコミットと前のコミットの 2 つが出て、前のコミットの中身が読めました。

$ git log --oneline -- .env
4655261 stop tracking ignored files
888e6a5 first
$ git show HEAD~1:.env
API_KEY=dummy-not-a-real-key

GitHub の文書は、消したい情報がパスワードやトークンなどの秘密なら、最初の手は、その秘密の失効(revoke)や差し替え(rotate)だと書いています。失効や差し替えをすれば、それで足りることもある、とも書いています。秘密を入れてしまったときの手順は、.env の記事にまとめました。履歴から消す方法は、この記事では扱いません。

git rm -r --cached . は関係のない変更も載せる

「全部やり直そう」と git rm -r --cached . のあとに git add . をすると、外したいファイルは外れますが、関係のない変更までステージに載ります。.env・app.log・main.txt をコミットしたあと、.gitignore(.env と *.log の 2 行)を作り、main.txt に 1 行足した(git add していない)状態で流しました。

$ git status --short
 M main.txt
?? .gitignore
$ git rm -r --cached .
rm '.env'
rm 'app.log'
rm 'main.txt'
$ git add .
$ git status --short
D  .env
A  .gitignore
D  app.log
M  main.txt

add していなかった main.txt の変更が、ステージに載りました。git add の前は M main.txt(M が右の列)、あとは M main.txt(M が左の列)の表示です。GitHub の文書は、うっかりコミットを避ける手として、git add . と git commit -a を避け、ファイルを名前で git add するよう書いています。

間違えて外したら(git restore --staged)

間違えて git rm --cached したら、コミットの前なら、git restore --staged <ファイル> で戻せます。.env と main.txt をコミットした状態で流しました。.gitignore を書かずに git rm --cached したので、D .env(インデックスからは消えた)と ?? .env(手元のファイルは、まだ追跡していない)の 2 行が出ています。

$ git rm --cached .env
rm '.env'
$ git status --short
D  .env
?? .env
$ git restore --staged .env
$ git status --short
$ git ls-files
.env
main.txt

Git の文書は、--staged を「インデックスだけを戻す。元は HEAD」と説明しています。取り消しの全体は、取り消しの記事にまとめました。

追跡していないのに無視されないときは?

追跡していないファイルなのに無視されないときは、git check-ignore -v ファイル名 で、どの行に当たるかを調べます。何も出なければ、どの行にも当たっていません(終了コードは 1)。終了コードの読み方は、.gitignore の書き方にまとめました。

次は、根(リポジトリのいちばん上のフォルダ)の .gitignore に *.log と build/、sub/ フォルダの中の .gitignore に !keep.log と /local.txt を書いたリポジトリです。-n を付けると、どの行にも当たらないファイルも出て、そのときは :: の形になります。

$ cat -n .gitignore
     1	*.log
     2	build/
$ cat -n sub/.gitignore
     1	!keep.log
     2	/local.txt
$ git check-ignore -v -n debug.log main.txt local.txt
.gitignore:1:*.log	debug.log
::	main.txt
::	local.txt

main.txt はどの行にも当たりません。local.txt は、根にあるファイルです。sub/.gitignore の /local.txt は、その sub/ の下のファイルにだけ効くので、根の local.txt には当たりません。パターンの書き方の決まりも、.gitignore の書き方にまとめました。

まだ作っていないファイルの名前でも、調べられます(末尾が / のパターンを、まだ無いフォルダで調べることは、試していません)。

$ git check-ignore -v not-yet-made.log
.gitignore:1:*.log	not-yet-made.log

出た行が、調べたファイルの親のフォルダに当たる行(logs/keep.log に logs/、logs/2026/keep.log に logs/*)のときは、親のフォルダが除外されています。logs フォルダの中に keep.log と a.log がある別のリポジトリで、logs/ と !logs/keep.log の 2 行を書いても、logs/keep.log は戻りません。

$ cat -n .gitignore
     1	logs/
     2	!logs/keep.log
$ git check-ignore -v logs/keep.log logs/a.log
.gitignore:1:logs/	logs/keep.log
.gitignore:1:logs/	logs/a.log

親のフォルダを除外すると、その中のファイルは ! で戻せません。直し方は、除外の除外(!)の記事で説明しています。

無視したくないのに無視されるときは?

無視したくないファイルが無視されるときも、git check-ignore -v で、どの行が当たっているかを見ます。出力は「元のファイル:行番号:パターン」と、タブのあとにパスが続く形です。出た行のパターン(行番号のあと)が ! で始まるときは、その行に当たって、無視されないという意味です。

元のファイルの欄で、どこに書かれた規則かが分かります。

  • .gitignore(リポジトリの根からの相対パス): そのフォルダの .gitignore です。下の例では .gitignore:1:*.log や sub/.gitignore:2:/local.txt の形で出ます
  • .git/info/exclude: 自分だけの規則です。worktree の中では、これも絶対パスで出ます。.git/info/exclude の記事で説明しています
  • 絶対パス: core.excludesFile で指したファイルです。設定しなくても読まれる ~/.config/git/ignore も、絶対パスで出ます。グローバルな .gitignore の記事で説明しています
$ git check-ignore -v debug.log sub/other.log sub/keep.log sub/local.txt local.txt notes.md build/out.js
.gitignore:1:*.log	debug.log
.gitignore:1:*.log	sub/other.log
sub/.gitignore:1:!keep.log	sub/keep.log
sub/.gitignore:2:/local.txt	sub/local.txt
.git/info/exclude:7:notes.md	notes.md
.gitignore:2:build/	build/out.js

絶対パスで出る例です。~/.config/git/ignore に .DS_Store と書いた環境です。出力の …/home は、この環境のホームのフォルダです。

$ git check-ignore -v .DS_Store
…/home/.config/git/ignore:1:.DS_Store	.DS_Store

規則の元が複数あるときの優先の順は、.git/info/exclude の記事にまとめました。

無視されているファイルを名前で git add すると、無視されたパスの一覧を出して止まります。-f(--force)を付けると、無視されているファイルでも足せます。Git 2.54.0 の表示は次のとおりです。

$ git add .env
The following paths are ignored by one of your .gitignore files:
.env
hint: Use -f if you really want to add them.
hint: Disable this message with "git config set advice.addIgnoredFile false"

手元の Mac の Git 2.39.3 では、最後の hint の行が、次の 2 行でした。ほかの行は同じです。

hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"

追跡したあとは、そのファイルに .gitignore は効きません(上の節のとおりです)。

よくある質問

.gitignore に書いてから git rm --cached しても大丈夫ですか?

GitHub の文書は、すでにコミットしたファイルを無視したいなら、無視の規則を足す前に追跡をやめる必要がある、と書いています。Git の gitignore の文書は、git rm --cached のあとで、ファイル名を .gitignore に足せる、と書いていて、順番を決まりとしては書いていません。この記事の手元の確かめでは、.gitignore を先に作ってから git rm --cached を流し、コミットしたあとで、そのファイルは無視されました。

.gitignore そのものはコミットしますか?

clone する人と規則を共有したいときは、.gitignore をコミットします。全員が無視したいものは、.gitignore に書く、と Git の文書にあります。自分だけで無視したいものは、リポジトリに入らない .git/info/exclude に書けます(.git/info/exclude の記事)。GitHub は、よく使う OS・環境・言語向けの .gitignore の一覧を、github/gitignore というリポジトリで公開しています。

「キャッシュを消す」とは何のことですか?

「.gitignore が効かないときはキャッシュを消す」という言い方は、Git の文書には見つかっていません。Git の用語集では、cache(キャッシュ)は index(インデックス)の古い呼び名で、index は作業ツリーを保存したもの、と説明されています。この記事の git rm --cached は、ファイルそのものではなく、インデックスからだけ外す操作です。手元のファイルは残ります。

追跡したまま、自分の変更だけ無視できますか?

Git には、その方法がありません。Git の FAQ は、Git がファイルを上書きするとき(checkout など)に、その変更が大事なものか捨ててよいものか分からないので、安全な側に倒して常に残すから、と説明しています。git update-index の assume-unchanged と skip-worktree は、この目的ではうまく動かないので、使わないと書かれています。

設定ファイルなら、ひな形(既定値のファイル)をリポジトリに入れ、それを写して変えたほうのファイルを無視する手がある、とも書かれています。

まとめ

  • .gitignore は、まだ追跡していないファイルにだけ効く。すでに追跡しているファイルは、.gitignore に書いても無視されない
  • 追跡しているかは、git ls-files --cached --ignored --exclude-standard に出るかと、git check-ignore -v に --no-index を付けたときと付けないときの違いで分かる
  • 追跡をやめるには git rm --cached <ファイル>(フォルダは -r)。外れるのはインデックスからだけで、手元のファイルは残る。.gitignore と一緒にコミットする
  • 手元の確かめでは、そのコミットを pull した側の手元からファイルが消え、過去のコミットには中身が残った。パスワードや API キーなら、先に失効・差し替え
  • 追跡していないのに効かないときは、git check-ignore -v で何も出ないか(どの行にも当たらない)、親のフォルダに当たる行が出るか(親の除外)を見る。無視したくないのに無視されるときは、出た行の元のファイルを見る
  • この記事で確かめていないこと: pull する側に手元の変更があるとき、VS Code・Sourcetree などの画面での操作、Windows、Git 2.56.0 での表示

参考資料

※この記事は、2026年10月23日時点の公式の資料と照らして確かめています。誤りに気づいたらお問い合わせからお知らせください。

PR
PR
タイトルとURLをコピーしました