よくある話:ゴミだらけのリポジトリ
チームの誰もが一度はこんな経験をしたことがあるはずだ:プルリクエストを開いてみると、diffが.DS_Store、Thumbs.db、IntelliJの.idea/ディレクトリだらけ、さらにひどい場合はAPIキーが入った.envファイルまでコミットされている。レビュアーはそのゴミの山をかき分けて、実際に変更されたコードを探さなければならない。
以前、誰も最初から.gitignoreをきちんと設定していないプロジェクトで働いたことがある。3ヶ月後、コミット履歴はnode_modules/でいっぱいになっていた。Windowsの開発者はThumbs.dbをコミットし、Macの開発者は.DS_Storeをコミットしていた。その後片付けに半日かかった——チーム全員にgit pull --rebaseを再実行してもらうよう説得する手間は言うまでもない。
しかし問題は見た目の悪さだけではない——本当に危険なケースもある。.envファイルがGitの履歴に入り込むのは深刻なセキュリティインシデントだ。後から削除しても履歴は残り、リポジトリへの読み取り権限を持つ人なら誰でもシークレットを取得できる。GitHubには露出したAPIキーを自動スキャンして無効化するメカニズムまで存在する——これが珍しいことではない証拠だ。
最もシンプルな解決策は、.gitignoreを二つのレベルで設定することだ:グローバル(自分のマシン)とプロジェクト別(リポジトリ)。この二つは互いを置き換えるものではなく、補完し合うものだ。
核心概念:.gitignoreの二つの層
1. グローバル.gitignore — 自分自身を守る
このファイルは個人のマシンに存在し、そのマシン上のすべてのリポジトリに適用される。ここには自分の作業環境に属するもの——プロジェクトではなく——を宣言する:
- OSファイル:
.DS_Store(macOS)、Thumbs.db、desktop.ini(Windows) - IDEファイル:
.idea/(JetBrains)、.vscode/(VS Code)、*.sublime-workspace - エディタの一時ファイル:
*.swp、*~(Vim/Emacs)
原則として、自分だけが使うツールでチームの誰も気にしないものはグローバルに入れる——チーム全員にあなたの代わりにignoreさせるべきではない。
2. プロジェクト.gitignore — チーム共通のルール
リポジトリのルートにある.gitignoreファイルはGitにコミットされ、全員に適用される。ここにはプロジェクトの言語、フレームワーク、ビルドツールに属するものを宣言する:
- ビルドディレクトリ:
dist/、build/、target/、__pycache__/ - 依存関係:
node_modules/、vendor/、.venv/ - 環境設定ファイル:
.env、.env.local、secrets.yaml - ログ、カバレッジ:
*.log、coverage/、.pytest_cache/
この境界線は思っている以上に重要だ。VS Codeユーザーは、プロジェクトリポジトリでVimユーザーに.vscode/をignoreさせるべきではない——それはグローバルgitignoreの仕事であり、プロジェクトのものではない。
実践的な詳細手順
ステップ1:グローバル.gitignoreの設定
ファイルを作成してGitに登録する:
# グローバルgitignoreファイルを作成
touch ~/.gitignore_global
# Gitに登録する
git config --global core.excludesFile ~/.gitignore_global
# 設定が反映されているか確認
git config --global core.excludesFile
# 出力:/home/youruser/.gitignore_global
~/.gitignore_globalの推奨内容:
# === macOS ===
.DS_Store
.AppleDouble
.LSOverride
Icon?
._*
# === Windows ===
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
# === Linux ===
*~
.fuse_hidden*
.Trash-*
# === JetBrains IDEs (IntelliJ, PyCharm, GoLand...) ===
.idea/
*.iml
*.iws
# === VS Code ===
.vscode/
!.vscode/extensions.json
# === Vim / Neovim ===
*.swp
*.swo
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
# === Emacs ===
\#*\#
.\#*
# === Sublime Text ===
*.sublime-workspace
!.vscode/extensions.jsonの行に注目しよう——!を使うと、ignoreされたディレクトリ内の特定のファイルをun-ignoreできる。extensions.jsonはプロジェクトの推奨拡張機能を一覧表示するファイルで、VS Code環境を統一するためにこれをコミットしたいチームも多い。ディレクトリ全体を盲目的にignoreしてから、後になって中のファイルを保持する必要があることに気づくのは避けたい。
ステップ2:プロジェクト別.gitignoreテンプレート
一から書く代わりに、gitignore.ioまたはGitHubのgitignoreテンプレートを使おう:
# curlを使ってPythonプロジェクトの.gitignoreを作成
curl -sL https://www.toptal.com/developers/gitignore/api/python,linux,macos > .gitignore
# またはGitHub CLI(インストール済みの場合)を使う
gh repo create --gitignore Python
Pythonプロジェクトのテンプレート(最も重要な部分):
# === Python ===
__pycache__/
*.py[cod]
*.pyo
*.pyd
.Python
# 仮想環境
.venv/
venv/
env/
.env/
# 配布 / パッケージング
build/
dist/
*.egg-info/
*.egg
# テスト
.pytest_cache/
.coverage
htmlcov/
.tox/
# 型チェック
.mypy_cache/
.pytype/
# Jupyter
.ipynb_checkpoints/
# 環境変数 — 絶対にコミットしないこと
.env
.env.local
.env.*.local
Node.jsプロジェクトのテンプレート:
# === Node.js ===
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# ビルド出力
dist/
build/
.next/
.nuxt/
# キャッシュ
.npm
.eslintcache
.parcel-cache/
# テスト
coverage/
# 環境変数
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
ステップ3:誤ってコミットしてしまったファイルの対処
.gitignoreに追加するだけでは、すでにGitで追跡されているファイルには不十分だ。Gitは引き続きそのファイルを追跡し続ける。追跡から削除する必要がある:
# ファイルを追跡から削除(ディスク上のファイルは保持)
git rm --cached path/to/file
# ディレクトリ全体を追跡から削除
git rm --cached -r node_modules/
# 現在の.gitignoreにマッチするが追跡されているすべてのファイルを削除
git ls-files -i --exclude-standard | xargs git rm --cached
# その後コミットする
git commit -m "chore: remove tracked files that should be gitignored"
APIキーを含む.envのような機密ファイルをうっかりリモートにプッシュしてしまった場合、削除してコミットし直すだけでは不十分だ。git-filter-repo(古いgitならgit filter-branch)を使って履歴全体から削除する必要がある。これはヒストリを書き換える操作であり、実行前にチーム全員に通知が必要だ。そして何があっても、露出したシークレットはすぐにローテーションすること——コミットした時点で侵害されたものとみなすべきだ。
ステップ4:モノレポや複雑なプロジェクトでの.gitignoreの整理
Gitでは任意のサブディレクトリに.gitignoreを配置できる——ルールはそのディレクトリ以下に適用される。モノレポを扱う際に便利だ:
my-monorepo/
├── .gitignore ← プロジェクト全体の共通ルール
├── frontend/
│ └── .gitignore ← フロントエンド(Node.js)専用ルール
└── backend/
└── .gitignore ← バックエンド(Python)専用ルール
子ファイルのルールは親ファイルのルールをオーバーライドできる。実例:ルートの.gitignoreが*.logをignoreしているが、backend/important.logを保持したい場合、backend/.gitignoreに追加するだけでよい:
# backend/.gitignore
!important.log
ステップ5:ルールの動作確認
ファイルがignoreされているかどうか不明な場合にデバッグに役立つコマンド:
# 特定のファイルがignoreされているかとその理由を確認
git check-ignore -v path/to/file
# 出力:.gitignore:5:*.log path/to/file
# (どのルールの何行目がマッチしているかを示す)
# ignoreされているすべてのファイルを表示
git ls-files --others --ignored --exclude-standard
# 追跡されているファイルを表示(ignoreされていないもの)
git ls-files
まとめ
プロジェクトの最初から.gitignoreを正しく設定することで、後々の多くの頭痛を防げる。シンプルな原則を覚えておこう:グローバルgitignoreはあなた個人のこと(OS、IDE、エディタ)を管理し、プロジェクトgitignoreはチーム全体のこと(言語、フレームワーク、シークレット)を管理する。
新しいプロジェクトを始める際に実践している3つの習慣がある。一つ目:gitignore.ioのテンプレートから.gitignoreを作成する。二つ目:まだそのファイルがなくても.env*をすぐに追加する。三つ目:他の何かを追加する前に、.gitignoreを最初のコミットとしてコミットする。2分で済むが、後の1週間分の後片付けを防げる。
新しいチームには、現在のプロジェクトの.gitignoreを15分見直してみる価値がある——たいてい追加すべきものやグローバルに移すべきものがいくつか見つかるはずだ。
