Skip to main content

リポジトリからの機微なデータの削除

Git リポジトリへのパスワードや SSH キーといった機密データをコミットする場合、そのデータを履歴から削除することができます。 不要なファイルをリポジトリの履歴から完全に削除するには、git filter-repo ツールか BFG Repo-Cleaner オープンソース ツールのいずれかを使用します。

git filter-repo ツールと BFG Repo-Cleaner によって、リポジトリの履歴が書き換えられます。これにより、変更した既存のコミットと依存するコミットの SHA が変更されます。 コミットの SHA を変更すると、リポジトリ内の開いている pull request に影響する場合があります。 リポジトリからファイルを削除する前に、開いているすべての pull request を結合または閉じることをお勧めします。

git rm を使用して、最新のコミットからファイルを削除することができます。 最新のコミットで追加されたファイルを削除する方法については、「GitHub の大きなファイルについて」を参照してください。

警告: この記事では、機密データを含むコミットに、GitHub.com のリポジトリ内のブランチまたはタグから到達できないようにする方法について説明しています。 ただし、こうしたコミットも、リポジトリのクローンやフォークからは、GitHub Enterprise Cloud でキャッシュされているビューの SHA-1 ハッシュによって直接、また参照元の pull request によって、到達できる可能性があります。 GitHub Enterprise Cloud では、リポジトリにある他のユーザーのクローンやフォークから機密データを削除することはできませんが、キャッシュされているビューや、pull request での機密データへの参照は、GitHub Support へ連絡することにより恒久的に削除することができます。

コミットを GitHub Enterprise Cloud にプッシュしたら、コミット内の機密データは侵害されたと見なすべきです。 パスワードをコミットした場合は変更してください。 キーをコミットした場合は、新たに生成してください。 侵害されたデータを削除しても、特にリポジトリの既存のクローンやフォークでの初期漏えいは解決されません。 リポジトリの履歴を書き換える場合は、これらの制限事項を考慮して決めてください。

ファイルをリポジトリの履歴からパージする

git filter-repo ツールまたは BFG Repo-Cleaner オープンソース ツールを使用し、リポジトリの履歴からファイルを消去します。

BFG を使用する

BFG Repo-Cleaner は、オープンソース コミュニティによって構築および管理されているツールです。 不要なデータを削除するための、git filter-branch より高速で簡単な代替手段が提供されます。

たとえば、機密データを含むファイルを削除して、最新のコミットをそのままにしておくには、次を実行します:

$ bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

リポジトリの履歴内の場所に関係なく、passwords.txt に一覧表示されているすべてのテキストを置き換えるには、以下を実行します。

$ bfg --replace-text passwords.txt

機密データが削除されたら、変更を GitHub Enterprise Cloud に強制的にプッシュする必要があります。 強制的にプッシュすると、リポジトリの履歴が書き換えられます。これにより、コミットの履歴から機密データが削除されます。 プッシュを強制すると、他のユーザーが作業のベースにしているコミットが上書きされる可能性があります。

$ git push --force

完全な使用方法とダウンロード手順については、BFG Repo-Cleaner のドキュメントを参照してください。

git filter-repo を使用する

警告: 変更の一時退避後に git filter-repo を実行すると、その他の stash コマンドを使用して変更を取得できなくなります。 git filter-repo を実行する前に、行ったすべての変更の一時退避を解除することをお勧めします。 最後に一時退避した一連の変更の一時退避を解除するには、git stash show -p | git apply -R を実行します。 詳細については、「Git ツール - 一時退避とクリーニング」を参照してください。

git filter-repo の動作を説明するために、リポジトリの履歴から機密データを含むファイルを削除し、それを .gitignore に追加して確実に、誤って再コミットされないようにする方法を示します。

  1. git filter-repo ツールの最新リリースをインストールします。 git-filter-repo は手動で、またはパッケージ マネージャーを使用してインストールすることができます。 たとえば、HomeBrew でツールをインストールするには、brew install コマンドを使用します。

    brew install git-filter-repo
    

    詳細については、newren/git-filter-repo リポジトリ内の INSTALL.md ファイルを参照してください。

  2. 履歴に機密データを含むリポジトリのローカル コピーがまだない場合は、ローカル コンピューターにリポジトリをクローンします。

    $ git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
    > Initialized empty Git repository in /Users/YOUR-FILE-PATH/YOUR-REPOSITORY/.git/
    > remote: Counting objects: 1301, done.
    > remote: Compressing objects: 100% (769/769), done.
    > remote: Total 1301 (delta 724), reused 910 (delta 522)
    > Receiving objects: 100% (1301/1301), 164.39 KiB, done.
    > Resolving deltas: 100% (724/724), done.
  3. リポジトリの作業ディレクトリに移動します。

    $ cd YOUR-REPOSITORY
  4. 次のコマンドを実行します。PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA は、ファイル名だけでなく、削除するファイルへのパス に置き換えてください。 これらの引数では、次のことが行われます。

    • すべてのブランチとタグの履歴全体を Git に強制的に処理させるが、チェックアウトはしない
    • 指定されたファイルと、結果として生成された空のコミットをすべて削除する
    • リモート URL など、 .git/config ファイルに格納されている一部の構成を削除する。 後で復元するために、このファイルを事前にバックアップすることができます。
    • 既存のタグを上書きする
      $ git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
        Parsed 197 commits
        New history written in 0.11 seconds; now repacking/cleaning...
        Repacking your repo and cleaning out old unneeded objects
        Enumerating objects: 210, done.
        Counting objects: 100% (210/210), done.
        Delta compression using up to 12 threads
        Compressing objects: 100% (127/127), done.
        Writing objects: 100% (210/210), done.
        Building bitmaps: 100% (48/48), done.
        Total 210 (delta 98), reused 144 (delta 75), pack-reused 0
        Completely finished after 0.64 seconds.

    注: (移動または名前が変更されたため) 他のパスに機密データが使用されたファイルが存在する場合は、これらのパスでもこのコマンドを実行する必要があります。

  5. 機密データを含むファイルを .gitignore に追加して確実に、誤って再度コミットしないようにします。

    $ echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
    $ git add .gitignore
    $ git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
    > [main 051452f] Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore
    >  1 files changed, 1 insertions(+), 0 deletions(-)
  6. リポジトリの履歴から必要なすべてを削除し、すべてのブランチがチェックアウトされていることを再確認します。

  7. リポジトリの状態に問題がなければ、ローカルの変更を強制的にプッシュして、GitHub.com リポジトリと、プッシュしたブランチをすべて上書きします。 コミットの履歴から機密データを削除するには、強制プッシュが必要です。

    $ git push origin --force --all
    > Counting objects: 1074, done.
    > Delta compression using 2 threads.
    > Compressing objects: 100% (677/677), done.
    > Writing objects: 100% (1058/1058), 148.85 KiB, done.
    > Total 1058 (delta 590), reused 602 (delta 378)
    > To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)
  8. タグ付けされたリリースから機密ファイルを削除するには、Git タグに対して強制的にプッシュする必要もあります。

    $ git push origin --force --tags
    > Counting objects: 321, done.
    > Delta compression using up to 8 threads.
    > Compressing objects: 100% (166/166), done.
    > Writing objects: 100% (321/321), 331.74 KiB | 0 bytes/s, done.
    > Total 321 (delta 124), reused 269 (delta 108)
    > To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)

GitHub からデータを完全に削除する

BFG ツールまたは git filter-repo を使用して機密データを削除し、変更を GitHub Enterprise Cloud にプッシュした後、GitHub Enterprise Cloud からデータを完全に削除するには、さらにいくつかの手順を実行する必要があります。

  1. GitHub Support に連絡し、GitHub Enterprise Cloud 上で、キャッシュされているビューと、プルリクエストでの機密データへの参照を削除するよう依頼します。 リポジトリの名前と削除する必要があるコミットへのリンクの両方またはいずれかを指定してください。

  2. 以前の (汚染された) リポジトリの履歴から、作成したブランチをマージ ではなくリベースするようにコラボレーターに指示します。 マージコミットを 1 回でも行うと、パージで問題が発生したばかりの汚染された履歴の一部または全部が再導入されてしまいます。

  3. 一定の時間が経過し、BFG ツール/git filter-repo に意図しない副作用がないことを確信したら、次のコマンドを使用して、ローカル リポジトリ内のすべてのオブジェクトが強制的に逆参照され、ガベージ コレクトされるようにします (Git 1.8.5 以降を使用)。

    $ git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
    $ git reflog expire --expire=now --all
    $ git gc --prune=now
    > Counting objects: 2437, done.
    > Delta compression using up to 4 threads.
    > Compressing objects: 100% (1378/1378), done.
    > Writing objects: 100% (2437/2437), done.
    > Total 2437 (delta 1461), reused 1802 (delta 1048)

    注: フィルター処理した履歴を、新規または空のリポジトリにプッシュして、GitHub Enterprise Cloud から新しいクローンを作成しても、同じことができます。

将来にわたって誤ったコミットを回避する

コミット対象でないものがコミットされるのを回避するためのシンプルな方法がいくつかあります。

  • GitHub Desktopgitk などのビジュアル プログラムを使用して変更をコミットします。 ビジュアルプログラムは通常、各コミットでどのファイルが追加、削除、変更されるかを正確に把握しやすくするものです。
  • コマンド ラインでの catch-all コマンド git add .git commit -a を回避するには、代わりに git add filenamegit rm filename を使用してファイルを個別にステージします。
  • git add --interactive を使用して、各ファイル内の変更を個別に確認およびステージします。
  • git diff --cached を使用して、コミットのステージした変更を確認します。 これは、git commit フラグを使用しない限り -a で生成される正確な差分です。

参考資料