Git/GitHub

.gitignore を書く

9

.gitignore を書く — Git Tips

.gitignore は、Git に「このパターンに一致するファイルは追跡しない」と伝える設定ファイルです。node_modules/.env のような、リポジトリに含めたくないものを git statusgit add . の対象から外せます。ただし すでに追跡済みのファイルには効きません。パターン、頻出テンプレート、誤って commit したファイルの外し方です。

参考: gitignore · Ignoring files · git-check-ignore · git-rm · github/gitignore


目次

  1. .gitignore が何をするか
  2. 置く場所
  3. パターンの書き方
  4. よく使うテンプレート
  5. git check-ignore でパターンを検証する
  6. すでに追跡されているファイルを外す
  7. .git/info/exclude との違い
  8. グローバルな .gitignore(core.excludesFile)
  9. よくある失敗

.gitignore が何をするか

.gitignore に書いたパターンに一致するファイル・フォルダは、次の 2 か所から除外されます。

対象 効果
git status の出力 Untracked files の一覧に出てこない
git add . / git add -A 一致するファイルは追加されない
git add <パス> 一致するファイルは通常拒否される(警告が出て終了コード 1)

一方で、次のケースには効きません

  • すでに git add / git commit されているファイル(後述の手順で個別に外す必要がある)
  • git add -f--force)で強制追加した場合.gitignore を無視して追加できる)

.gitignore は「これから追跡されるのを防ぐ」ためのファイルであり、「一度追跡された履歴を消す」機能ではありません。


置く場所

最も基本的な置き方は リポジトリのルート直下 に 1 つ置く方法です。

my-project/├── .gitignore       ← ここ├── src/├── package.json└── README.md

Git は .gitignoreサブディレクトリにも複数置く ことができ、それぞれ「そのディレクトリ以下」に適用されます。大きなモノレポでフォルダごとに無視ルールを変えたい場合に便利ですが、個人開発やチーム開発の最小構成では ルートに 1 つ で十分なことが多いです。

my-project/├── .gitignore           ← リポジトリ全体向け└── packages/    └── app/        └── .gitignore   ← packages/app 以下だけに追加ルール

パターンの書き方

.gitignore の 1 行は 1 パターンで、シェルのグロブに近い記法を使います。

記法 意味
* 任意の文字列(/ を除く) *.log → 拡張子 .log 全て
? 任意の 1 文字 data?.csvdata1.csv など
/(先頭) リポジトリルートからの相対パスに固定 /build → ルート直下の build のみ
/(末尾) ディレクトリのみに一致 logs/ → ファイルの logs には一致しない
** 任意の深さのディレクトリ **/temp → どの階層の temp にも一致
!(先頭) 直前までの除外を打ち消す(再度追跡対象にする) !important.log
#(先頭) コメント行 # ビルド出力

具体例で挙動を確認します。

# ログファイルはどこにあっても無視*.log# ルート直下の build フォルダだけ無視(サブフォルダの build は対象外)/build# 名前が logs のディレクトリはどの階層でも無視**/logs/# *.log で無視されるが、この 1 ファイルだけは追跡したい!important.log

否定パターン(!)の注意点: 親ディレクトリごと無視している場合、そのディレクトリ内のファイルを ! で個別に復活させることはできません。Git はディレクトリ自体が無視されていると、中身を走査しないためです。復活させたいファイルがある階層は、ディレクトリではなくファイル単位で無視するように書き換える必要があります。

# NG: dist ディレクトリ自体を無視すると、中の keep.txt を !dist/keep.txt で戻せないdist/# OK: ディレクトリの中身を無視しつつ、特定ファイルだけ残すdist/*!dist/keep.txt

よく使うテンプレート

言語・エディタ・OS ごとに、無視すべき定番パターンがあります。プロジェクトの技術構成に合わせて必要な行だけ組み合わせます。

Node.js / npm

node_modules/npm-debug.log*dist/build/.env.env.local

Python

__pycache__/*.pyc.venv/venv/*.egg-info/

OS が作る不要ファイル

# macOS.DS_Store# WindowsThumbs.dbDesktop.ini

エディタ / IDE

.vscode/.idea/*.swp

秘密情報系(最重要)

.env.env.local.env.*.local*.pem*.key

.env や秘密鍵は、.gitignore に入れておくだけでは すでに commit 済みなら追跡が止まりません。新規プロジェクトでは、最初の commit の前にこれらの行を .gitignore に入れておくのが最も安全です。GitHub 公式は言語・フレームワーク別のテンプレートを github/gitignore にまとめており、プロジェクト作成時にそのまま流用できます。


git check-ignore でパターンを検証する

パターンを書いても「効いているのか、効いていないのか」が分かりにくいことがあります。git check-ignore -v を使うと、どのファイルがどの .gitignore のどの行によって無視されているかを確認できます。

git check-ignore -v node_modules/react/package.json
.gitignore:1:node_modules/    node_modules/react/package.json

出力は「一致した .gitignore ファイル : 行番号 : パターン」→「対象パス」の順です。一致しない場合は何も出力されず、終了コードが 1 になります。

git check-ignore -v src/App.tsxecho $LASTEXITCODE   # PowerShell

PowerShell では終了コードは $LASTEXITCODE、bash / Git Bash では $? で確認できます。

git check-ignore -v src/App.tsxecho $?

複数ファイルをまとめて調べたい場合はパスを並べます。

git check-ignore -v *.log .env dist/index.js

「無視されているはずのファイルが git status に出てくる」というときは、まずこのコマンドで期待どおりのパターンに一致しているかを確認すると原因が特定しやすくなります。


すでに追跡されているファイルを外す

.envnode_modules/.gitignore に書く前に commit してしまった 場合、.gitignore を追加しただけでは Git はそのファイルの追跡をやめません。すでにインデックス(追跡対象)に載っているファイルは、明示的に外す必要があります。

手順

# 1. .gitignore に対象パターンを追加しておくecho ".env" >> .gitignore# 2. インデックスからだけ外す(ディスク上のファイルは残す)git rm --cached .env# 3. .gitignore ごとコミットgit add .gitignoregit commit -m ".env を追跡対象から外す"

git rm --cached--cached が重要です。付けずに git rm .env を実行すると、ディスク上のファイルも削除されてしまいます。ディレクトリごと外したい場合は -r を付けます。

git rm -r --cached node_modulesgit add .gitignoregit commit -m "node_modules を追跡対象から外す"

PowerShell でも同じコマンドがそのまま使えます。

git rm --cached .envgit rm -r --cached node_modulesgit add .gitignoregit commit -m "追跡対象の整理"

注意: 履歴には残る

git rm --cachedこれ以降のコミット で追跡を止めるだけで、過去のコミットに含まれた内容そのものは履歴に残り続けます。すでに GitHub などへ push 済みの秘密情報(APIキー・パスワードなど)は、この手順だけでは消えません。漏えいした値は 無効化・再発行 し、履歴からの完全な削除が必要な場合は git filter-repo などの履歴改変ツールを使いますが、これは共有リポジトリでは影響が大きいため、まずは値の失効を優先してください。


.git/info/exclude との違い

.gitignore の他に、.git/info/exclude という同じ書式のファイルがあります。役割はほぼ同じですが、次の違いがあります。

項目 .gitignore .git/info/exclude
Git 管理 される(commit・push でチームに共有される) されない(.git フォルダ内・ローカル専用)
用途 チーム全員が無視すべきパターン 自分だけの一時的な無視設定(メモ用のスクリプトなど)

チーム全体で共有したいルールは .gitignore に、自分のローカル環境だけで使う一時ファイル(実験用スクリプトなど)を無視したい場合は .git/info/exclude に書く、という使い分けができます。

# .git/info/exclude の例(自分のローカルメモ用フォルダを無視)scratch/

グローバルな .gitignore(core.excludesFile)

OS やエディタが生成するファイル(.DS_StoreThumbs.db.vscode/ など)は、プロジェクトごとに .gitignore へ書くより、全リポジトリ共通のグローバル設定にしておくと管理が楽になります。

# グローバル用の .gitignore ファイルを用意git config --global core.excludesFile ~/.gitignore_global

Windows(PowerShell)の場合、ホームディレクトリは環境変数 $HOME または $env:USERPROFILE で参照できます。

git config --global core.excludesFile "$env:USERPROFILE\.gitignore_global"

作成したファイルに、OS・エディタ由来の共通パターンを書いておきます。

# ~/.gitignore_global の例.DS_StoreThumbs.db.vscode/.idea/

このファイルは Git 管理外(各プロジェクトの .gitignore には含まれない)なので、プロジェクトごとの .gitignore はプロジェクト固有のパターンだけに絞り、OS・エディタ由来のノイズはグローバル側にまとめる、という分担がきれいです。


よくある失敗

.gitignore に書いたのに git status に出てくる

原因はほぼ次の 2 つです。

  1. すでに追跡済みすでに追跡されているファイルを外す の手順で git rm --cached する
  2. パターンの書き方の間違いgit check-ignore -v <パス> で一致するか確認する
git check-ignore -v path/to/file

何も出力されなければ、そのファイルは現在のどの .gitignore にも一致していません。パターンのタイプミス、パス区切りの向き、末尾の / の有無を見直します。

Windows でパスの区切り文字が原因で一致しない

.gitignore のパターンは / 区切りで書きます。Windows のパス表示(\)をそのまま貼り付けると一致しません。

# NG(Windows のパス表示をそのまま貼った)build\output# OKbuild/output

無視しているはずのファイルが追加されてしまった

通常の git add(パス指定を含む)は .gitignore に一致するファイルを拒否します。それでも追加できている場合は、git add -f--force)を使っていないか、シェルのエイリアスやスクリプトを確認します。すでにステージされている場合は git restore --staged <パス> で戻せます。

# 通常は拒否される(-f が必要、という hint が出る)git add secret.env# 強制追加した場合の取り消しgit restore --staged secret.env

node_modules を消したら他の人の環境で動かなくなった

.gitignore で無視するのは正しい運用ですが、node_modules 自体は各環境で npm install(または pnpm install / yarn install)によって再生成される前提です。package.jsonpackage-lock.json(または pnpm-lock.yaml / yarn.lock)は 必ず追跡対象に残すことで、他の環境でも同じ依存関係を再現できます。

.env.example まで無視されてしまった

.env* のような広いパターンを書くと、テンプレートとして共有したい .env.example まで無視されることがあります。否定パターンで復活させます。

.env.env.local.env.*.local!.env.example

ディレクトリ単位で無視している場合は、パターンの書き方 で触れたとおり、ディレクトリ丸ごとの否定はできない点に注意してください。

シェア