結論(すでにコミットされているものを監視対象外にする)
どちらの場合も 作業ディレクトリ上のファイルやフォルダは消えません(インデックス=次のコミットに載せる一覧から外すだけです)。**まだ一度も Git に載せていない(未追跡)**だけなら、手順2は不要で .gitignore だけでよいです。
-
.gitignoreにパターンを書く(今後、未追跡の同名パスを拾わないため)。ディレクトリをまとめて無視する意味では、末尾に/を付ける書き方がよく使われます。単一ファイルのとき(パスは置き換え):
echo 'path/to/secret.env' >> .gitignoreディレクトリごとのとき(パスは置き換え):
echo 'path/to/build-output/' >> .gitignore -
インデックスから追跡だけをやめる。 単一ファイルなら
git rm --cached <ファイル>、ディレクトリごとならgit rm -r --cached <ディレクトリ>(-rがないとディレクトリを扱えません)。例:単一ファイル
git rm --cached path/to/secret.env例:ディレクトリごと
git rm -r --cached path/to/build-output/ -
.gitignoreの変更をステージしてコミットする(手順2の「追跡やめ」はこの時点ですでにステージされている)。内容は必要なら先にgit statusで確認する。単一ファイルのとき:
git add .gitignore && git commit -m "Stop tracking path/to/secret.env"ディレクトリごとのとき:
git add .gitignore && git commit -m "Stop tracking path/to/build-output/"
公式の詳細は gitignore および git-rm を参照してください。
メイン: なぜ .gitignore だけでは足りないか
.gitignore は原則として 未追跡のパスに対して効きます。すでにコミットされて追跡中のパスは、ルールを足しただけでは追跡が続きます。監視対象から外すには、上の結論どおり ファイルなら git rm --cached、ディレクトリなら git rm -r --cached でインデックスから外す操作が別途必要です。
.gitignore を書いたのに「すぐ反映されない」ように見える
.gitignore は 次の Git コマンドを実行するときに読まれます。設定ファイルの再読み込みを「待つ」タイプの遅延は基本的にありません。
それでも無視されないように見える典型は次のとおりです。
- すでに追跡されているパス … 上記のとおり、追跡解除は
git rm --cached/git rm -r --cached側の話。 - パターンが合っていない … 先頭の
/、ディレクトリ指定、**、否定!などで、想定と違うマッチになることがあります。 - エディタやツールの表示 … ファイルツリーがキャッシュしていると、見た目の更新が遅れることがあります(Git の無視ルールとは別レイヤーです)。
補足: なぜ git rm -r --cached . は避けた方がよいか
git rm -r --cached . は、「無視したいパスだけ」を外すコマンドではありません。カレント以下に追跡されているエントリをまとめてインデックスから外す操作です。
そのため次のような 運用・レビュー上のデメリットがあります。
- 差分の意図が読みにくい … リポジトリ全体に相当する変更が一度にステージに載り、レビューで「何を追跡から外したいのか」が埋もれやすい。
- 正しい手順が「外してから全部入れ直す」になりがち … チームや将来の自分にとって、個別パスを外す手順より説明コストが高い。
実務では、外したいディレクトリやファイルに絞った git rm -r --cached <path> の方が、意図と差分が揃いやすく、事故も起きにくいです。
補足: git rm -r --cached . をした場合に起きやすい問題
ここでは 実際に手を滑らせたときのリスクを整理します。
-
インデックス上、大量のパスが「削除」扱いになる
そのあとgit add .などで入れ直すまで、git diff --cachedや変更ファイル数が一気に膨れます。入れ直しまで正しく終えていれば意味のある差分は絞られますが、途中状態が扱いにくいです。 -
git addの入れ忘れ
追跡を続けたいファイルを漏れなく戻さないと、次のコミットでリポジトリからそのパスが消えた扱いになります(ローカルファイルは残っていても、以降のコミットに載らない)。 -
サブモジュールや sparse checkout などがあると想定外になりやすい
一括で触るため、個別パスに比べて環境依存のつまずきが出やすいです。 -
「個別パスと最終形は同じにできる」が、そこに到達するまでのリスクが違う
インデックスとツリーが最終的に同じ形になれば追跡の付け方は揃えられますが、途中のステージの見え方と入れ忘れリスクは.の方が大きいです。
よくある誤解: 追跡から外したら、それまでの履歴は消えるか
消えません。 git rm や git rm --cached は これ以降のコミットにそのパスを載せない方向の操作で、すでに記録されたコミットのオブジェクトは書き換えません。
過去のコミットを辿れば、そのファイルの内容は参照できます。パスが最新コミットに存在しない場合、git log の指定の仕方で履歴が拾いにくくなることはあるので、必要なら git log --follow -- path などを使います。
履歴そのものを消すのは、git filter-repo などの 履歴書き換えの話で、追跡解除とは別です。
まとめ
結論(追跡済みを外す): .gitignore を書く + ファイルなら git rm --cached <ファイル>、ディレクトリなら git rm -r --cached <dir>/ + .gitignore をステージしてコミット。未追跡なら .gitignore のみ。
| 論点 | 要点 |
|---|---|
.gitignore | 主に 未追跡向け。追跡済みは ファイルは git rm --cached、ディレクトリは git rm -r --cached でインデックスから外す。 |
| 反映のタイミング | ルールは 次の操作で読まれる。追跡済みは「書いただけ」では変わらない。 |
git rm -r --cached . | 全パスをいったん外すので差分が膨れやすく、入れ忘れ・想定外が起きやすい。<path> に絞るのが無難。 |
| 履歴 | 過去のコミットは残る。以降そのパスを載せないだけ。 |
誤ってコミットした node_modules などをやめたいだけなら、そのパスだけ git rm -r --cached し、.gitignore を整える、で足ります。