Gitで間違えてコミットした機密情報を完全に削除する方法【履歴からも消す】

「あ、やってしまった…」

APIキーや顧客情報、データベースのパスワードなど、Gitに絶対にコミットしてはいけない機密情報を間違えてコミットしてしまった経験はありませんか?

しかも、そのコミットをリモートリポジトリにプッシュしてしまっていたら、git resetで取り消すだけでは不十分です。Git履歴には情報が残り続け、誰でもアクセスできる状態になってしまいます。

この記事では、Gitに誤ってコミットした個人情報や機密情報を履歴から完全に削除する方法を、実務で使える手順として解説します。

目次

まず確認:どんな情報をコミットしてしまったか

個人情報の例

  • 顧客名簿(氏名、住所、電話番号、メールアドレス)
  • 社員情報
  • 個人を特定できるログファイル
  • マイナンバーや身分証明書のスキャンデータ

機密情報の例

  • APIキー・アクセストークン
  • データベースの接続情報(パスワード含む)
  • 秘密鍵(SSH、SSL証明書など)
  • 環境変数ファイル(.env)
  • 社内の機密文書
  • クライアントの契約書や見積書

【重要】リモートリポジトリにプッシュ済みの場合

情報はすでに外部に公開されている可能性があります。

  • GitHubなどのPublicリポジトリ:即座に漏洩とみなしてください
  • Privateリポジトリ:アクセス権のあるメンバー全員に見られている状態です
  • フォークされている場合:フォーク先にも情報が残っています

この状況を正しく理解した上で、次のステップに進みましょう。

まず最初にやるべきこと

1. 該当の認証情報を無効化する

機密情報を削除する前に、まず情報自体を無効化しましょう。

  • APIキー → サービス側で無効化・再発行
  • パスワード → すぐに変更
  • アクセストークン → 無効化して新規作成
  • 秘密鍵 → 無効化して新しい鍵ペアを生成

なぜ先に無効化するのか?

Git履歴から削除しても、誰かがすでに情報をコピーしている可能性があるためです。
まずは情報そのものを使えなくすることが最優先です。

2. 被害範囲を確認する

以下の項目をチェックしてください。

# いつコミットしたかを確認
git log --all --full-history -- "*config.json*"

# リモートの状態を確認
git remote -v
git log origin/main

# ブランチ一覧を確認
git branch -a

確認すべきポイントとしては以下です。

  • いつコミットしたか
  • リモートにプッシュしたか
  • 誰がリポジトリにアクセスできるか
  • フォークされていないか(GitHubの場合)
  • プルリクエストに含まれていないか

Git履歴から完全削除する3つの方法

方法1:git filter-branch(標準機能)

メリット: Gitに標準搭載されているコマンド
デメリット: 処理が遅い、非推奨になりつつある

# 特定のファイルを履歴から完全削除
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch config/.env" \
  --prune-empty --tag-name-filter cat -- --all

手順の解説

  1. --index-filter:インデックスから削除
  2. git rm --cached --ignore-unmatch:ファイルが存在しない場合もエラーを出さない
  3. config/.env:削除したいファイルのパス
  4. --prune-empty:空になったコミットを削除
  5. --all:すべてのブランチに適用

複数ファイルを削除する場合

git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch config/.env config/secrets.json" \
  --prune-empty --tag-name-filter cat -- --all

実行後のクリーンアップ

# 古い参照を削除
rm -rf .git/refs/original/

# reflogを削除
git reflog expire --expire=now --all

# ガベージコレクション実行
git gc --prune=now --aggressive

方法2:BFG Repo-Cleaner(おすすめ)

メリット: 高速、使いやすい、初心者にもわかりやすい
デメリット: 別途インストールが必要

インストール(macOS)

brew install bfg

インストール(Windows)

BFG公式サイトからJARファイルをダウンロードしてください。

使い方

# 1. リポジトリをクローンミラー形式
git clone --mirror https://github.com/username/repo.git

# 2. リポジトリディレクトリに移動
cd repo.git

# 3. 特定ファイルを削除
bfg --delete-files config.json

# または特定の拡張子のファイルを一括削除
bfg --delete-files "*.env"

# または特定のフォルダ内のファイルをすべて削除
bfg --delete-folders config

# 4. Git履歴をクリーンアップ
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# 5. リモートに強制プッシュ
git push --force
```

**実際の出力例:**
```
Using repo : /Users/username/repo.git

Found 1234 objects to protect
Found 5 commit-pointing refs : HEAD, refs/heads/main, ...

Protected commits
-----------------

These are your latest commits, and so their contents will NOT be removed from your BFG-cleaned repository.

Cleaning
--------
Found 15 commits
Protecting blob ids from commits : 5 found

  config.json
    before: 2.5 KB
    after:  removed

Updating 15 Commit objects
  Commit tree dirt-ification complete

Updating references: 100% (5/5)
...

BFG run is complete!

特定の文字列を削除する場合

# パスワードなどの文字列を削除
bfg --replace-text passwords.txt
```

**passwords.txtの例:**
```
password123
sk-abc123xyz456
DATABASE_PASSWORD=secret123

方法3:git filter-repo(最新推奨)

メリット: 高速で安全、Gitコミュニティ推奨、柔軟な設定が可能
デメリット: Pythonが必要

インストール

# macOS/Linux
pip install git-filter-repo --break-system-packages

# またはHomebrewから
brew install git-filter-repo

使い方1:特定ファイルを削除

# 特定ファイルを履歴から削除
git filter-repo --path config/.env --invert-paths

# 複数ファイルを削除
git filter-repo --path config/.env --path secrets.json --invert-paths

# 特定のディレクトリを削除
git filter-repo --path config/ --invert-paths

使い方2:特定の文字列を置換

# replacements.txtファイルを作成
cat > replacements.txt << EOF
password123===>***REMOVED***
sk-abc123xyz===>***REMOVED***
DATABASE_URL=postgresql://user:pass@localhost===>***REMOVED***
EOF

# 置換を実行
git filter-repo --replace-text replacements.txt

使い方3:正規表現で置換

# expressions.txtファイルを作成
cat > expressions.txt << EOF
regex:password\s*=\s*[^\s]+===>password=***REMOVED***
regex:api_key\s*=\s*[^\s]+===>api_key=***REMOVED***
EOF

# 置換を実行
git filter-repo --replace-text expressions.txt

実行後の確認

# 履歴を確認
git log --all --oneline

# 特定のファイルが削除されたか確認
git log --all -- config/.env

どの方法を選ぶべき?

  • 初心者・シンプルに削除したい → BFG Repo-Cleaner
  • 細かい制御が必要・大規模リポジトリ → git filter-repo
  • すぐに使いたい・インストール不要 → git filter-branch

個人的には、BFG Repo-Cleanerが最も使いやすく、エラーも少ないのでおすすめです。

リモートリポジトリへの反映

履歴を書き換えたら、リモートリポジトリにも反映させる必要があります。

1. 強制プッシュの実行

# すべてのブランチに強制プッシュ
git push origin --force --all

# タグも強制プッシュ
git push origin --force --tags

注意: 強制プッシュは他のメンバーの作業に影響を与えます。必ず事前に連絡してください。

2. プロテクトされたブランチの場合

mainブランチなどがプロテクトされている場合、GitHub/GitLabの設定を一時的に変更する必要があります。

GitHubの場合

  1. リポジトリの Settings → Branches
  2. Branch protection rules で該当ブランチを選択
  3. 「Allow force pushes」を一時的に有効化
  4. 強制プッシュを実行
  5. 設定を元に戻す

GitLabの場合

  1. Settings → Repository → Protected Branches
  2. 該当ブランチの「Allowed to force push」を一時的に有効化
  3. 強制プッシュを実行
  4. 設定を元に戻す

3. GitHub/GitLabでの追加対応

GitHubの場合

プルリクエストにも履歴が残るため、以下を確認してください。

  1. Closed/Merged PRに機密情報が含まれていないか確認
  2. 含まれている場合はPRをDeleteする
  3. フォークされている場合は各Fork所有者に連絡

GitHubのキャッシュ削除を依頼

GitHubは内部的にコミットをキャッシュしているため、履歴を書き換えてもアクセスできる場合があります。

GitHub Supportに連絡して、以下の情報を伝えてください。

件名Request to remove cached commits containing sensitive data

本文
Repository: https://github.com/username/repo
Commit SHA: abc123def456 (削除したいコミットのハッシュ)
Reason: Accidentally committed API keys and need to remove from GitHub cache

Could you please remove this commit from GitHub's cache?

GitLabの場合

GitLab Cleanupという機能が使えます。

  1. Settings → Repository → Repository cleanup
  2. 削除したいオブジェクトのリストをアップロード
  3. Cleanupを実行

チーム開発での注意点

1. チームメンバーへの連絡

履歴の書き換えは、他のメンバーの作業に大きな影響を与えます。必ず事前に連絡しましょう。

メールのテンプレート

件名:【重要Gitリポジトリの履歴書き換えを実施しました

プロジェクトメンバー各位

本日機密情報が誤ってコミットされていたためGitリポジトリの履歴書き換えを実施しました

対象リポジトリ
https://github.com/username/project-name

理由
機密情報APIキーが含まれていたためセキュリティ対策として削除しました

お願い
以下の手順で対応をお願いします

1. 現在の作業内容をすべてコミットプッシュ
2. ローカルのリポジトリをバックアップ
   mv project-name project-name_backup
3. リポジトリを再クローン
   git clone https://github.com/username/project-name.git
4. 必要に応じて作業中のブランチを再作成

作業期限
本日中にお願いします

ご不便をおかけしますがセキュリティ上の理由のため
ご理解とご協力をお願いいたします

質問があればいつでもご連絡ください

2. 他のメンバーが実施すべき作業

作業手順

# 1. 現在の作業をコミット
git add .
git commit -m "WIP: 作業中の内容を保存"

# 2. ローカルリポジトリをバックアップ
cd ..
mv myproject myproject_backup

# 3. 新しくクローン
git clone https://github.com/username/myproject.git
cd myproject

# 4. 作業中のブランチがあれば再作成
git checkout -b feature/my-work

# 5. バックアップから必要なファイルをコピー
# (機密情報を含まないファイルのみ
cp -r ../myproject_backup/src/components ./src/

エラーが出る場合

# もしdivergent branchesエラーが出たら
git fetch origin
git reset --hard origin/main

# それでもダメなら完全にクリーンな状態に
rm -rf .git
git clone https://github.com/username/myproject.git new_clone

3. フォークへの対応

リポジトリがフォークされている場合、フォーク先にも機密情報が残ります。

対応方法

1. GitHubでフォークの一覧を確認(Insights → Forks)
2. 各フォーク所有者に連絡
3. 同様の手順で履歴を書き換えてもらう
4. または、元のリポジトリを削除して新規作成

連絡のテンプレート

件名Security Issue - Please update your fork

Hello,

I've discovered that our repository contained sensitive information 
(API keys) in the commit history. I've cleaned the main repository, 
but your fork still contains this data.

Could you please:
1. Delete your current fork
2. Fork the repository again from the cleaned version

Or, if you have important changes:
1. Follow the same cleanup process I used
2. Let me know when it's done

Thank you for your understanding.

今後、同じミスを防ぐための対策

一度機密情報を漏洩させてしまうと、完全に取り戻すことはできません。予防が最も重要です。

1. .gitignoreの設定

プロジェクトのルートに.gitignoreファイルを作成し、機密情報を含むファイルを除外しましょう。

# 環境変数ファイル
.env
.env.local
.env.development
.env.production
.env.*.local

# 設定ファイル
config/database.yml
config/secrets.json
config/credentials.yml.enc
application.properties

# 認証情報
*.pem
*.key
*.p12
*.pfx
id_rsa
id_rsa.pub
*.crt
credentials.json
service-account.json

# AWSクレデンシャル
.aws/credentials
.aws/config

# ログファイル
*.log
logs/
log/

# データベースファイル
*.sql
*.sqlite
*.sqlite3
*.db

# バックアップファイル
*.bak
*.backup
*.old

# OS固有ファイル
.DS_Store
Thumbs.db
desktop.ini

# IDEの設定ファイル
.vscode/settings.json
.idea/
*.swp
*.swo

# 顧客データ
customers/
user_data/
exports/

すでにトラッキングされているファイルを除外する場合

# Gitの追跡から削除ファイル自体は残す
git rm --cached .env

# .gitignoreに追加
echo ".env" >> .gitignore

# コミット
git add .gitignore
git commit -m "Add .env to .gitignore"

2. git-secretsの導入

AWS Labsが開発した、機密情報のコミットを防ぐツールです。

インストール

# macOS
brew install git-secrets

# Linux
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets
sudo make install

リポジトリに設定

# プロジェクトディレクトリで実行
cd /path/to/repo
git secrets --install

# AWSのキーパターンを登録
git secrets --register-aws

# カスタムパターンを追加
git secrets --add 'password\s*=\s*.+'
git secrets --add 'api_key\s*=\s*.+'
git secrets --add 'secret\s*=\s*.+'
git secrets --add '[A-Za-z0-9+/]{40}'  # Base64エンコードされた文字列

すべてのリポジトリに適用

# グローバル設定
git secrets --install ~/.git-templates/git-secrets
git config --global init.templateDir ~/.git-templates/git-secrets

既存の履歴をスキャン

git secrets --scan-history

もし検出されたら…

[ERROR] Matched one or more prohibited patterns

File: config/database.yml
Line: password=secret123

この場合、すぐに履歴から削除する必要があります。

3. pre-commitフックの設定

コミット前に自動チェックを実行するフックを設定します。

# .git/hooks/pre-commit ファイルを作成
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

# .envファイルのコミットを防ぐ
if git diff --cached --name-only | grep -E '\.(env|pem|key)$'; then
  echo "❌ Error: 機密情報を含む可能性のあるファイルをコミットしようとしています"
  echo ""
  git diff --cached --name-only | grep -E '\.(env|pem|key)$'
  echo ""
  echo "これらのファイルを .gitignore に追加してください"
  exit 1
fi

# パスワードや秘密鍵などの文字列をチェック
if git diff --cached | grep -iE '(password|secret|api_key|private_key)\s*[:=]'; then
  echo "⚠️  Warning: パスワードやAPIキーが含まれている可能性があります"
  echo ""
  git diff --cached | grep -iE '(password|secret|api_key|private_key)\s*[:=]'
  echo ""
  read -p "本当にコミットしますか? (y/N): " -n 1 -r
  echo
  if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    exit 1
  fi
fi

# AWSアクセスキーのパターンをチェック
if git diff --cached | grep -E 'AKIA[0-9A-Z]{16}'; then
  echo "❌ Error: AWSアクセスキーが検出されました"
  exit 1
fi

echo "✅ Pre-commit check passed"
EOF

# 実行権限を付与
chmod +x .git/hooks/pre-commit

Pythonでより高度なチェックをする場合

# pre-commitフレームワークをインストール
pip install pre-commit

# .pre-commit-config.yaml を作成
cat > .pre-commit-config.yaml << 'EOF'
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: check-added-large-files
        args: ['--maxkb=1000']
      - id: detect-private-key
      - id: check-json
      - id: check-yaml

  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']
EOF

# フックをインストール
pre-commit install

# 実行テスト
pre-commit run --all-files

4. 環境変数の管理方法

機密情報は環境変数として管理し、コードには含めないようにしましょう。

開発環境:.envファイル

# .env.example を作成テンプレート
cat > .env.example << 'EOF'
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
API_KEY=your_api_key_here
SECRET_KEY=your_secret_key_here
EOF

# .envファイルをコピーして使用
cp .env.example .env

# .envを編集して実際の値を入力
# このファイルは .gitignore に含める

本番環境:環境変数として設定

# Herokuの場合
heroku config:set API_KEY=actual_key_value

# AWS Elastic Beanstalkの場合
aws elasticbeanstalk set-environment --environment-name my-env \
  --option-settings Namespace=aws:elasticbeanstalk:application:environment,\
  OptionName=API_KEY,Value=actual_key_value

# Dockerの場合
docker run -e API_KEY=actual_key_value myapp

コードでの読み込み

// Node.js
require('dotenv').config();
const apiKey = process.env.API_KEY;

// Python
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv('API_KEY')

// Ruby
require 'dotenv/load'
api_key = ENV['API_KEY']

5. GitHub/GitLabのSecret Scanning

GitHubの場合

  1. リポジトリの Settings → Security → Code security and analysis
  2. 「Secret scanning」を有効化(Publicリポジトリは自動、Privateは有料プラン)
  3. アラートが表示されたら即座に対応

検出される情報の例

  • GitHubトークン
  • AWSアクセスキー
  • Google APIキー
  • Stripe APIキー
  • Slackトークン
  • など100種類以上

GitLabの場合

  1. Settings → CI/CD → Secret Detection
  2. 有効化して、パイプラインで自動スキャン

6. チーム内でのルール作り

技術的な対策だけでなく、チーム内でルールを共有することも重要です。

例:セキュリティガイドライン

# セキュリティガイドライン

## 絶対にコミットしてはいけないもの
- パスワードAPIキートークン
- 秘密鍵証明書
- 顧客の個人情報
- .envファイル

## コミット前のチェックリスト
.gitignoreに必要なファイルが含まれているか
git diffで機密情報が含まれていないか確認
pre-commitフックが動作しているか

## もし機密情報をコミットしてしまったら
1. すぐにチームリーダーに報告
2. 該当の認証情報を無効化
3. 履歴から削除このドキュメント参照
4. チームに連絡

## 定期レビュー
- 月1回リポジトリをスキャン
- .gitignoreの見直し
- 不要な古いブランチの削除

機密情報をコミットしてしまった時のチェックリスト

万が一、機密情報をコミットしてしまった場合は、このチェックリストに従って対応してください。

□ 該当の認証情報を無効化・変更した
□ 被害範囲を確認した(いつ、どこに、誰が)
□ Git履歴から完全削除した(BFG/filter-repo/filter-branch)
□ ローカルのreflogとキャッシュをクリーンアップした
□ リモートに強制プッシュした
□ チームメンバーに連絡し、再クローンを依頼した
□ プルリクエストに含まれていないか確認した
□ フォークされたリポジトリを確認・対応依頼した
□ GitHubのキャッシュ削除をサポートに依頼した
□ .gitignoreを見直し、追加した
□ git-secretsを導入した
□ pre-commitフックを設定した
□ 再発防止策をチームで共有した
□ インシデントレポートを作成した(企業の場合)

よくある質問

Q1. GitHubにプッシュしてしまった機密情報は完全に消えますか?

A. 履歴を書き換えてもGitHubのキャッシュに残る可能性があります。

GitHubは内部的にコミットをキャッシュしており、コミットハッシュを知っていれば直接アクセスできる場合があります。

対応方法

  1. GitHubサポートに連絡してキャッシュの削除を依頼
  2. または、リポジトリを削除して新規作成(最終手段)

Q2. すでにフォークされている場合はどうすればいい?

A. フォーク所有者に連絡して同様の対応をお願いするか、リポジトリを削除して新規作成することを検討してください。

フォークは独立したリポジトリなので、元のリポジトリを修正してもフォークには反映されません。

対応方法

  1. GitHub上でフォークの一覧を確認(Insights → Network → Forks)
  2. 各フォーク所有者に連絡
  3. 同様の手順で履歴を書き換えてもらう
  4. 難しい場合は、リポジトリを削除して新規作成

Q3. git filter-branch、BFG、git filter-repoの違いは?

A. 以下のように使い分けてください。

ツール速度使いやすさ推奨度特徴filter-branch遅い難しい△標準機能、非推奨BFG速い簡単◎初心者向け、エラーが少ないfilter-repo最速普通◎公式推奨、柔軟性が高い

個人的には、BFG Repo-Cleanerが最も使いやすく、エラーも少ないのでおすすめです。

Q4. ローカルだけで、まだプッシュしていない場合は?

A. git resetでコミットを取り消すだけでOKです。

# 直前のコミットを取り消す変更内容は残る
git reset --soft HEAD~1

# または変更内容も含めて完全に取り消す
git reset --hard HEAD~1

ただし、念のため機密情報(APIキーなど)は変更しておきましょう。

Q5. 「divergent branches」エラーが出た場合は?

A. 履歴を書き換えた後によく出るエラーです。強制的にリモートの状態に合わせましょう。

# リモートの最新状態を取得
git fetch origin

# ローカルブランチを完全にリモートに合わせる
git reset --hard origin/main

# それでもダメなら再クローン
cd ..
rm -rf myproject
git clone https://github.com/username/myproject.git

Q6. 大量のファイルを削除したい場合は?

A. BFGやfilter-repoでパターンマッチングを使うと効率的です。

# BFGで拡張子指定
bfg --delete-files "*.{env,key,pem}"

# filter-repoで正規表現
git filter-repo --path-regex '^config/.*\.(env|key)$' --invert-paths

Q7. 企業で機密情報を漏洩させてしまった場合は?

A. すぐに上司とセキュリティ担当者に報告してください。

企業の場合、以下の対応が必要になることがあります。

  1. インシデントレポートの作成
  2. 情報セキュリティ委員会への報告
  3. 影響範囲の調査
  4. 顧客への通知(個人情報の場合)
  5. 再発防止策の策定

隠さずに迅速に報告することが最も重要です。

結論

Gitに機密情報をコミットしてしまうのは、誰にでも起こりうるミスです。

大切なのは

  1. 焦らず、まず認証情報を無効化する
    • Git履歴から削除しても、情報がすでに漏れている可能性があります
    • まずは情報そのものを使えなくすることが最優先
  2. 正しい手順で履歴から完全削除する
    • BFG Repo-Cleaner、git filter-repo、git filter-branchから選択
    • 初心者にはBFGがおすすめ
    • 必ずリモートにも強制プッシュ
  3. 再発防止策を導入する
    • .gitignoreの徹底
    • git-secretsやpre-commitフックの導入
    • チーム内でのルール共有

この記事の手順に従えば、個人情報や機密情報を安全に削除できます。

ただし、一度外部に漏れた情報は完全には取り戻せません
日頃から.gitignoreやgit-secretsで予防することが最も重要ですね。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次