Git 履歴から機密ファイルとそのコミットを削除する
-
22-08-2019 - |
質問
Git プロジェクトを GitHub に置きたいのですが、機密データ (capistrano の /config/deploy.rb などのユーザー名とパスワード) を含む特定のファイルが含まれています。
これらのファイル名を追加できることはわかっています .gitignore, ただし、これによって Git 内の履歴は削除されません。
また、/.git ディレクトリを削除して最初からやり直すこともしたくありません。
削除する方法はありますか 全て Git 履歴に特定のファイルの痕跡はありますか?
解決
あらゆる実用的な目的のために、 初め あなたが心配すべきことは パスワードを変更してください! あなたの質問からは、git リポジトリが完全にローカルであるのか、それとも別の場所にリモート リポジトリがあるのかは明らかではありません。それがリモートであり、他の人から保護されていない場合は、問題が発生します。これを修正する前に誰かがそのリポジトリのクローンを作成した場合、その人のパスワードのコピーがローカル マシンに保存されることになり、履歴から削除された「修正」バージョンへの更新を強制することはできません。安全にできる唯一の方法は、パスワードを使用したことがある場所でパスワードを別のパスワードに変更することです。
それはさておき、修正方法は次のとおりです。 GitHub は FAQ としてまさにその質問に答えました:
Windows ユーザー向けの注意事項:このコマンドでは単一引用符の代わりに二重引用符 (") を使用してください
git filter-branch --index-filter \
'git update-index --remove filename' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force
このコードを GitHub などのリモート リポジトリにプッシュし、他の人がそのリモート リポジトリのクローンを作成すると、履歴を書き換える状況になることに注意してください。この後、他の人が最新の変更をプルダウンしようとすると、早送りではないため変更を適用できないことを示すメッセージが表示されます。
これを修正するには、既存のリポジトリを削除してクローンを再作成するか、「上流リベースからの回復」の手順に従う必要があります。 git-rebase マンページ.
将来、機密情報を含む変更を誤ってコミットしたが、気づいた場合には 前に リモート リポジトリにプッシュする場合、より簡単な修正がいくつかあります。最後にコミットしたのが機密情報を追加したコミットである場合は、単純に機密情報を削除してから、次のコマンドを実行します。
git commit -a --amend
これにより、実行したファイル全体の削除など、行った新しい変更で以前のコミットが修正されます。 git rm
. 。変更が履歴にさらに遡っているにもかかわらず、リモート リポジトリにプッシュされていない場合は、対話型リベースを実行できます。
git rebase -i origin/master
これにより、リモート リポジトリとの最後の共通祖先以降に行ったコミットが含まれるエディタが開きます。機密情報を含むコミットを表す行の「pick」を「edit」に変更し、保存して終了します。Git は変更を順を追って確認し、次のことができる場所に移動します。
$EDITOR file-to-fix
git commit -a --amend
git rebase --continue
機密情報を含む変更ごとに。最終的にはブランチに戻り、新しい変更を安全にプッシュできます。
他のヒント
パスワードを変更することは良い考えですが、リポジトリの履歴からパスワードを削除するプロセスについては、 BFG リポクリーナー, 、より高速かつ簡単な代替手段 git-filter-branch
Git リポジトリからプライベート データを削除するために明示的に設計されています。
を作成します private.txt
削除するパスワードなどをリストしたファイル (1 行に 1 つのエントリ) を作成し、次のコマンドを実行します。
$ java -jar bfg.jar --replace-text private.txt my-repo.git
リポジトリの履歴内でしきい値サイズ (デフォルトでは 1MB) 未満のすべてのファイルがスキャンされ、一致する文字列 (リポジトリにないもの) がスキャンされます。 最新 commit) は文字列「***REMOVED***」に置き換えられます。その後、使用できます git gc
死んだデータを削除するには:
$ git gc --prune=now --aggressive
BFG は通常、実行より 10 ~ 50 倍高速です。 git-filter-branch
オプションは簡素化され、次の 2 つの一般的な使用例に合わせて調整されています。
- 削除中 クレイジーなビッグファイル
- 削除中 パスワード、資格情報 & 他の 個人データ
完全な開示:私は BFG Repo-Cleaner の作者です。
私はこのスクリプト デビッド・アンダーヒルで、私にとっては魅力のように働きました。
それは背後にあるままに混乱を一掃するために加算natacadoのフィルタ分岐にこれらのコマンドを追加します:
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
全スクリプト(デビッド・アンダーヒルへのすべてのクレジット)
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune
以下に変更された場合は、最後の2つのコマンドは、より良い仕事があります:
git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
GitHub にプッシュした場合は、強制プッシュだけでは不十分です。リポジトリを削除するか、サポートにお問い合わせください。
1秒後に強制的に押しても、以下に説明するように十分ではありません。
有効なアクションは次のとおりです。
漏洩したのはパスワードのような変更可能な資格情報ですか?
- はい:パスワードをすぐに変更し、OAuth キーと API キーをさらに使用することを検討してください。
いいえ(裸の写真):
リポジトリ内のすべての課題が無効になっても構いませんか?
- いいえ:リポジトリを削除する
はい:
- サポート問い合わせ先
- リークがあなたにとって非常に重大である場合、リークの可能性を低くするためにリポジトリのダウンタイムが多少発生しても構わないと考えている場合、 プライベートにする GitHub サポートからの返信を待つ間
次の理由により、1 秒後に強制的にプッシュするだけでは十分ではありません。
GitHub は長期間にわたってコミットをぶら下げ続けます。
ただし、GitHub スタッフに連絡すれば、そのような未解決のコミットを削除する権限があります。
私がこのことを身をもって体験したのは、 すべての GitHub コミットメールをリポジトリにアップロードしました 彼らは私にそれを削除するように頼んだので、私はそうしました、そして彼らは
gc
. 。データを含むプルリクエスト ただし削除する必要があります:このため、最初の削除後 1 年間はリポジトリ データにアクセスできたままでした。未解決のコミットは、次のいずれかの方法で確認できます。
- コミットWeb UI: https://github.com/cirosantilli/test-dangling/commit/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (ウェイバックマシン)
- API: https://api.github.com/repos/cirosantilli/test-dangling/commits/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (ウェイバックマシン)
そのコミット時にソースを取得する便利な方法の 1 つは、ダウンロード zip メソッドを使用することです。これは、任意の参照を受け入れることができます。例: https://github.com/cirosantilli/myrepo/archive/SHA.zip
次のいずれかの方法で、欠落している SHA を取得できます。
- API イベントをリストする
type": "PushEvent"
. 。例えば。私の: https://api.github.com/users/cirosantilli/events/public (ウェイバックマシン) - 場合によっては、コンテンツを削除しようとしたプル リクエストの SHA を確認すると便利です。
- API イベントをリストする
のようなスクレーパーがあります http://ghtorrent.org/ そして https://www.githubarchive.org/ GitHub データを定期的にプールし、別の場所に保存します。
彼らが実際のコミット差分をスクレイピングしているかどうかはわかりませんでした。データが多すぎるためその可能性は低いですが、技術的には可能です。NSA とその関係者は、人物や関心のあるコミットにリンクされたものだけをアーカイブするフィルターを備えている可能性があります。
ただし、強制プッシュするのではなくリポジトリを削除すると、API からもコミットがすぐに消えて 404 が返されます。 https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 これは、同じ名前で別のリポジトリを再作成した場合でも機能します。
これをテストするために、リポジトリを作成しました。 https://github.com/cirosantilli/test-dangling そしてこうしました:
git init
git remote add origin git@github.com:cirosantilli/test-dangling.git
touch a
git add .
git commit -m 0
git push
touch b
git add .
git commit -m 1
git push
touch c
git rm b
git add .
git commit --amend --no-edit
git push -f
以下も参照してください。 GitHub から未解決のコミットを削除するにはどうすればよいですか?
明確にしておきます:受け入れられた答えは正しいです。まずは試してみてください。ただし、ユースケースによっては、特に「致命的」などの不快なエラーが発生した場合には、不必要に複雑になる可能性があります。悪いリビジョン --prune-empty' か、リポジトリの履歴をまったく気にしません。
代替案は次のようになります。
- プロジェクトのベースブランチに cd します
- 機密性の高いコード/ファイルを削除します
- rm -rf .git/#コードからすべてのgit情報を削除する
- github に移動してリポジトリを削除します
- このガイドに従って、通常どおりコードを新しいリポジトリにプッシュします。https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
もちろん、これにより、すべてのコミット履歴ブランチと、github リポジトリとローカル git リポジトリの両方からの問題が削除されます。これが受け入れられない場合は、別のアプローチを使用する必要があります。
これを核オプションと呼びます。
ここに私の解決策は、
ウィンドウにありますgitのフィルタ分岐--treeフィルター "のrm -f 'FILEDIR /ファイル名'" HEAD
Gitのプッシュ--force
のパスが正しいことを確認してください それ以外の場合は動作しません。
私はそれが役に立てば幸い。
を使用するのフィルタ分岐の
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all
git push origin *branch_name* -f
あなたはgit forget-blob
を使用することができます。
使い方は非常に簡単git forget-blob file-to-forget
です。あなたがここでの詳細情報を取得することができます。
<のhref = "https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/" のrel =」 noreferrer "> https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/ の
それはそうと、
であなたの歴史、REFLOG、タグ内のすべてのコミットから消えます私はすべての今して、同じ問題に遭遇し、毎回私は、プロセスを自動化された理由です、バックこの記事や他の人に来ている。
私は一緒にこれを置くために許さスタックオーバーフローからの貢献者にクレジット
これまでに何度かこの作業をしなければなりませんでした。これは一度に 1 つのファイルに対してのみ機能することに注意してください。
ファイルを変更したすべてのコミットのリストを取得します。一番下にあるものが最初のコミットになります。
git log --pretty=oneline --branches -- pathToFile
履歴からファイルを削除するには、最初のコミット sha1 と前のコマンドのファイルへのパスを使用し、これらを次のコマンドに入力します。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..
だから、それは次のようになります
git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore
のgitから追跡されたファイルのキャッシュを削除し、リストを
.gitignore
し、そのファイルを追加します。
私のアンドロイドのプロジェクトでは、私が持っていたの admob_keys.xmlのアプリ/ srcに/メイン/ resを/値は、/ のフォルダに分けxmlファイルとしての。私は、スクリプトの下に使用し、完全に働いたこの機密ファイルを削除します。
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all