mcpField
K
keeping-git-repos-clean

keeping-git-repos-clean

github.com/wdm0006開発10961 回インストール2 日前に更新
リポジトリ

keeping-git-repos-clean について

開発者やメンテナー向けに、秘密情報や生成物、個人用ファイルを Git リポジトリに含めない方法をまとめたスキルです。追跡対象の監査、安全な除外、認証情報のローテーション、検証後の変更確認を扱います。

主な機能

  1. 01追跡ファイルの秘密情報や生成物の監査
  2. 02ローカルコピーを残して追跡解除
  3. 03漏えいした認証情報の先行ローテーション
  4. 04グローバル除外とコミット時スキャン
  5. 05検証前後のリポジトリ状態確認

活用シーン

  1. 01追跡済みの秘密情報や一時ファイルの発見
  2. 02ローカルファイルを安全に追跡解除
  3. 03履歴に残った認証情報漏えいへの対応
  4. 04生成物がレビュー対象に混ざるのを防止

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wdm0006/python-skills --skill keeping-git-repos-clean

インストール後、Claude Code で/keeping-git-repos-cleanを入力して読み込まれたか確認します。

詳細

Git リポジトリをクリーンに保つ

リポジトリに入り込みがちなファイルは、大きく分けてシークレットと開発用アーティファクトの 2 種類です。 どちらも事前に防ぐのは簡単ですが、後から片付けるのは大変です。Git の履歴は残り続け、公開リポジトリではすべてが公開されるためです。

みんなが忘れがちな唯一のルール

.gitignore は、すでにコミット済みのファイルの追跡を停止しません。 パスを .gitignore に追加しても、防げるのは今後、追跡されていないファイルがステージングされることだけです。Git がすでに追跡しているファイルは、その後もコミットされ続けます。これは何度も問題になります。たとえば .env が .gitignore に記載されていても、そのルールが追加される前にコミットされていたため、公開され続けることがあります。

ローカルのコピーを残したまま、ファイルの追跡を実際に停止するには:

git rm --cached path/to/file        # untrack, leave working-tree copy in place
git rm -r --cached some/dir/        # for a directory
echo "path/to/file" >> .gitignore   # then ignore it so it doesn't come back
git commit -m "Stop tracking <file>; add to .gitignore"

重要なのは --cached フラグです。通常の git rm は作業コピーも削除します。

リポジトリが実際に追跡しているものを監査する

何がクリーンかを判断するために .gitignore を信用せず、インデックスを直接確認してください:

git ls-files | grep -iE '\.(env|pem|key|p12|profraw|log|bak|db|sqlite3?)$'
git ls-files | grep -iE '(^|/)(\.DS_Store|~\$|todo\.db|node_modules/|__pycache__/)'
git ls-files '*.db' '*.sqlite*'                 # scratch databases
git ls-files | xargs -I{} du -h {} | sort -rh | head   # surprisingly large tracked files

実際のリポジトリでよく見かける要注意ファイル:

  • シークレット: 有効なトークンを含む .env、設定モジュールにハードコードされた AWS_*/DB の認証情報、本番環境に含まれた SECRET_KEY = "CHANGEME"/"foobar" などのプレースホルダー。
  • ビルドアーティファクト: LaTeX の .aux/.toc/.log/.synctex.gz/.pdf、LLVM の *.profraw、コンパイル済みバイナリ、htmlcov/、dist/、*.egg-info/。
  • 一時ファイル/個人用アーティファクト: todo.db などのツール固有の一時 SQLite DB、エディターのバックアップ(*.backup、*.bak、Word のロックファイル ~$*.docx)、紛れ込んだ *.log。
  • OS の不要ファイル: .DS_Store、Thumbs.db。

シークレットには git rm だけでは不十分です

HEAD からシークレットを削除しても、履歴からは削除されません。git log -p や、シークレットを追加したコミットから、引き続き閲覧できます。以下の 3 つを順番に行う必要があります。そのうち、実際に保護につながるのは最初の手順だけです。

  1. 認証情報をローテーションします。 リモートに一度でも送られたシークレットは、漏えいしたものとして扱ってください。新しいトークン/キー/パスワードを発行し、古いものを無効にします。まずこれを行ってください。漏えいした値は、プッシュされた時点で公開されているためです。
  2. 今後の追跡を停止します(git rm --cached + .gitignore + 必要な環境変数をプレースホルダー値のみで記載した .env.example)。
  3. 必要に応じて履歴を消去します(git filter-repo --invert-paths --path .env、または BFG を使用)し、強制プッシュします。これにより SHA が書き換えられ、共同作業者に影響するため、通常は認証情報のローテーション後にメンテナーが意図的に行う作業であり、自動化された PR では行いません。

(2)と(3)を実施しても(1)を省略した PR は、誤った安心感を与えます。値は引き続き有効で、履歴を含むクローンやフォークにも残っています。ローテーションが人による対応として必須であることを、必ず明記してください。

「コミット済み」は「公開済み」を意味します

公開リポジトリでは、特に path: '.' でデプロイされる静的サイト(GitHub Pages はリポジトリ全体をアップロードします)の場合、追跡対象のファイルはすべて公開 URL から取得できます。サイトのリポジトリのルートにある一時ファイル todo.db は、/todo.db として配信されます。公開リポジトリにコミットする前に、誰でもダウンロードできるものと考えてください。

予防策:グローバル ignore +シークレットスキャナー

エディターファイル、OS ファイル、todo.db のようなツールの一時 DB など、開発者ごとに発生する不要ファイルは、各プロジェクトの .gitignore ではなくグローバルに無視するべきです。そうすれば、どのリポジトリにも入り込みません:

git config --global core.excludesFile ~/.gitignore_global
printf '%s\n' '.DS_Store' '*.swp' 'todo.db' '*.profraw' >> ~/.gitignore_global

シークレットが履歴に残るのを防ぐため、コミット時に pre-commit フックでブロックしてください:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks: [{id: gitleaks}]
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.5.0
    hooks: [{id: detect-secrets, args: ["--baseline", ".secrets.baseline"]}]

スタータープロジェクト用の .gitignore(これをコミットしてください):

# Secrets / local config
.env
.env.*
!.env.example
*.pem
*.key

# Python build/test artifacts
__pycache__/
*.py[cod]
build/
dist/
*.egg-info/
.coverage
htmlcov/
.pytest_cache/

# Scratch / OS / editor
*.db
*.sqlite
*.sqlite3
*.profraw
*.log
*.bak
*.backup
.DS_Store
~$*

検証によって作業ツリーが汚れることがあります

コンパイラー、テストランナー、アセットパイプラインは、変更の検証だけを目的としたコマンドであっても、チェックアウト内にファイルを書き込むことがよくあります。無視されていないキャッシュファイルを作成したり、PDFやコンパイル済みCSSなどの追跡対象の配布物を再生成したりすることがあります。コマンドが成功しても、作業ツリーに自分の変更だけが残っているとは限りません。

検証の前後に状態を確認し、レビューしたパスだけをステージングしてください。

git status --short
make test                         # or the project's real build command
git status --short
git diff -- path/you/changed
git add path/you/changed          # never sweep in generated files with git add -A
git diff --cached --check
git diff --cached --stat

ツールが必然的に大量の出力を生成する場合は、チェックアウトの使い捨てコピーで実行してください。これにより、実際のビルドを維持しつつ、生成ファイルがパッチに混入するのを防げます。

scratch_dir=$(mktemp -d)
rsync -a --exclude .git ./ "$scratch_dir/"
(cd "$scratch_dir" && make build)

検証によって、意図的に対象外としている追跡対象の生成物が変更された場合は、差分を確認した後に限り、その正確なパスだけを復元してください。

git diff -- docs/manual.pdf
git restore -- docs/manual.pdf

クリーンアップに広範囲な復元やリセットを使用しないでください。チェックアウトには、すでに他の人の作業が含まれている可能性があります。また、未追跡の生成物のクリーンアップに git stash を頼らないでください。通常のスタッシュでは未追跡ファイルが除外されます。また、--include-untracked を指定しても、stash pop の前に再生成されたファイルと競合することがあります。既知の生成パスは、明示的に生成を防ぐか削除してください。

チェックリスト

Audit:
- [ ] `git ls-files` reviewed for secrets, build output, scratch DBs, OS files
- [ ] No live credentials in tracked source or .env
- [ ] No surprisingly large/binary tracked files

Remediate (if dirty):
- [ ] Secret rotated/revoked FIRST (history is public the moment it was pushed)
- [ ] `git rm --cached` + .gitignore entry for each offending file
- [ ] .env.example documents required vars with placeholder values only
- [ ] History scrub flagged as a maintainer follow-up if the secret is in history

Prevent:
- [ ] Project .gitignore covers secrets, build artifacts, OS/editor noise
- [ ] Global core.excludesFile catches per-developer scratch files
- [ ] gitleaks / detect-secrets pre-commit hook installed
- [ ] Verification bracketed by `git status --short`; only reviewed paths staged

ソースコードの脆弱性やハードコードされたシークレットのパターンをスキャンする場合は、auditing-python-security スキルを参照してください。このスキルの対象は、Gitが追跡するものです。

コメント