ドキュメントには頻繁に更新が加えられ、その都度公開されています。本ページの翻訳はまだ未完成な部分があることをご了承ください。最新の情報については、英語のドキュメンテーションをご参照ください。本ページの翻訳に問題がある場合はこちらまでご連絡ください。

機密データをリポジトリから削除する

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

git filter-branch コマンドと BFG Repo-Cleaner は、リポジトリの履歴を書き換えます。変更を加えた既存のコミットや依存関係にあるコミットの SHA を変更します。 コミットの SHA が変更されると、リポジトリでオープンされたプルリクエストに影響する可能性があります。 ファイルをリポジトリから削除する前に、オープンプルリクエストをすべてマージまたはクローズすることを推奨します。

git rm によって、最新のコミットからファイルを削除することができます。 最新のコミットに追加されたファイルの削除の詳しい情報については、「リポジトリの履歴からファイルを削除する」を参照してください。

警告: コミットを GitHub Enterprise にプッシュしたら、そこに含まれるデータが危険にさらされることを考慮する必要があります。パスワードをコミットした場合は、変更してください。 キーをコミットした場合は、新たに生成してください。

この記事では、機密データを含むコミットに GitHub Enterprise リポジトリのブランチやタグから到達できないようにする方法を説明しています。 ただし、こうしたコミットも、リポジトリのクローンやフォークからは、GitHub Enterprise でキャッシュされているビューの SHA-1 ハッシュによって直接、また参照元のプルリクエストによって、到達できる可能性があることに注意することが重要です。 GitHub Enterprise では、リポジトリに既存のクローンやフォークについては何もできませんが、キャッシュされているビューや、プルリクエストでの機密データへの参照は、GitHub Enterprise サイト管理者 へ連絡することにより恒久的に削除することができます。

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

BFG を使用する

BFG Repo-Cleaner は、オープンソースコミュニティによって構築およびメンテナンスされているツールです。 これは、不要なデータを削除する手段として、git filter-branch より高速でシンプルです。 たとえば、機密データを含むファイルを削除して、最新のコミットをそのままにしておくには、次を実行します:

$ bfg --delete-files 機密データを含むファイル

passwords.txt にリストされているすべてのテキストについて、リポジトリの履歴にあれば置き換えるには、次を実行します:

$ bfg --replace-text passwords.txt

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

filter-branch を使用する

警告: 変更を stash した後に git filter-branch を実行した場合、他の stash コマンドで変更を取得することはできなくなります。 git filter-branch を実行する前に、加えた変更を unstash するようおすすめします。 stash した最後の一連の変更を unstash するには、git stash show -p | git apply -R を実行します。 詳しい情報については、Git Tools Stashing を参照してください。

git filter-branch がどのように機能するかを図解するため、機密データを含むファイルをリポジトリの履歴から削除し、.gitignore に追加することで、誤って再コミットされないようにするための方法を示します。

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

    $ git clone https://hostname/ユーザ名/リポジトリ> Initialized empty Git repository in /Users/ファイルパス/リポジトリ/.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.
  2. リポジトリのワーキングディレクトリに移動します。

    $ cd リポジトリ
  3. 次のコマンドを実行します。機密データを含むファイルへのパスは、ファイル名だけではなく、削除するファイルへのパスで置き換えます。 その引数により、次のことが行われます:

    • 各ブランチとタグの履歴全体を強制的に Git で処理するが、チェックアウトはしない
    • 指定のファイルを削除することにより、生成された空のコミットも削除される
    • 既存のタグを上書きする

      $ git filter-branch --force --index-filter \
        "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" \
        --prune-empty --tag-name-filter cat -- --all
        > Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (266/266)
        > Ref 'refs/heads/master' was rewritten

    メモ: 機密データを含む当該ファイルが (移動されたか名前が変更されたため) 他のパスに存在していた場合、このコマンドはそのパスでも実行する必要があります。

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

    $ echo "機密データを含むファイル" >> .gitignore
    $ git add .gitignore
    $ git commit -m "Add 機密データを含むファイル to .gitignore"
    > [master 051452f] Add 機密データを含むファイル to .gitignore
    >  1 files changed, 1 insertions(+), 0 deletions(-)
  5. リポジトリの履歴から削除対象をすべて削除したこと、すべてのブランチがチェックアウトされたことをダブルチェックします。

  6. リポジトリの状態が整ったら、ローカルでの変更をフォースプッシュして、GitHub Enterprise リポジトリと、プッシュしたすべてのブランチに上書きします。

    $ 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://hostname/ユーザ名/リポジトリ.git
    >  + 48dc599...051452f master -> master (forced update)
  7. 機密データをタグ付きリリースから削除するため、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://hostname/ユーザ名/リポジトリ.git
    >  + 48dc599...051452f master -> master (forced update)
  8. GitHub Enterprise サイト管理者 に連絡し、GitHub Enterprise 上で、キャッシュされているビューと、プルリクエストでの機密データへの参照を削除するよう依頼します。

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

  10. 一定の時間が経過し、git filter-branch に意図しない副作用がないことが確信できるようになったら、次のコマンドによって、ローカルリポジトリのすべてのオブジェクトが強制的に参照から外されガベージコレクトされるようにします (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)

    Note: You can also achieve this by pushing your filtered history to a new or empty repository and then making a fresh clone from GitHub Enterprise.

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

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

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

参考リンク

担当者にお尋ねください

探しているものが見つからなかったでしょうか?

弊社にお問い合わせください