GitHubにGitプロジェクトを配置したいのですが、機密データ(ユーザー名とパスワード、capistranoの/config/deploy.rbなど)を含む特定のファイルが含まれています。
これらのファイル名を.gitignoreに追加できることはわかっていますが、Git内の履歴は削除されません。
また、/。gitディレクトリを削除してやり直したくありません。
Git履歴で特定のファイルのすべてのトレースを削除する方法はありますか?
GitHubにGitプロジェクトを配置したいのですが、機密データ(ユーザー名とパスワード、capistranoの/config/deploy.rbなど)を含む特定のファイルが含まれています。
これらのファイル名を.gitignoreに追加できることはわかっていますが、Git内の履歴は削除されません。
また、/。gitディレクトリを削除してやり直したくありません。
Git履歴で特定のファイルのすべてのトレースを削除する方法はありますか?
回答:
すべての実用的な目的で、最初に心配する必要があるのはパスワードの変更です!gitリポジトリが完全にローカルであるかどうか、またはリモートリポジトリが他の場所にまだあるかどうかは、質問からは明らかではありません。それがリモートで他から保護されていない場合、問題があります。これを修正する前に誰かがそのリポジトリのクローンを作成した場合、そのローカルマシンにはパスワードのコピーがあり、履歴から削除された「修正済み」バージョンに強制的に更新することはできません。安全な唯一の方法は、パスワードを使用したすべての場所でパスワードを変更することです。
それを解決するために、これを修正する方法を次に示します。GitHubはFAQとしてその質問に正確に答えました:
Windowsユーザーへの注意:このコマンドでは、単一引用符ではなく二重引用符( ")を使用して ください。
git filter-branch --index-filter \
'git update-index --remove PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force
アップデート2019:
これは、FAQの現在のコードです。
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
git push --force --verbose --dry-run
git push --force
このコードをGitHubなどのリモートリポジトリにプッシュすると、他のユーザーがそのリモートリポジトリのクローンを作成すると、履歴を書き換えるようになります。この後、他のユーザーが最新の変更をプルダウンしようとすると、早送りではないため変更を適用できないことを示すメッセージが表示されます。
これを修正するには、既存のリポジトリを削除して再クローンするか、git-rebaseマンページの「UPSREAM REBASEからのリカバリ」の手順に従う必要があります。
ヒント:実行git rebase --interactive
将来、誤って機密情報の変更をコミットしたが、リモートリポジトリにプッシュする前に気付いた場合は、いくつかの簡単な修正があります。機密情報を追加するのが最後のコミットである場合は、機密情報を削除してから、次のコマンドを実行します。
git commit -a --amend
これにより、以前に行われたコミットが、で行われたファイル全体の削除を含む、行った新しい変更で修正されますgit rm
。変更がさらに履歴に戻っているにもかかわらず、リモートリポジトリにプッシュされていない場合は、インタラクティブなリベースを実行できます。
git rebase -i origin/master
これにより、リモートリポジトリの最後の共通の祖先以降に行ったコミットでエディターが開きます。機密情報を含むコミットを表すすべての行で「選択」を「編集」に変更し、保存して終了します。Gitは変更をウォークスルーし、次のことができる場所に移動します。
$EDITOR file-to-fix
git commit -a --amend
git rebase --continue
機密情報を含む変更ごと。最終的には、ブランチに戻り、新しい変更を安全にプッシュできます。
filter-branch
コードとあなたがリンクしたgithubページのコードとの間にはいくつかの実質的な違いがあるようです。たとえば、3行目--prune-empty --tag-name-filter cat -- --all
。ソリューションが変更されたか、何か不足していますか?
<introduction-revision-sha1>..HEAD
は機能しません。2番目以降のコミットからのみファイルを削除します。(どのように私は、最初のコミットの範囲にコミット含まれていますか?)方法は、ここで指摘されている割引:help.github.com/articles/... 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
パスワードを変更することは良い考えですが、リポジトリの履歴からパスワードを削除するプロセスのために、Gitリポジトリからプライベートデータを削除するために明示的に設計されたより高速でシンプルな代替手段であるBFG Repo-Cleanerをお勧めしgit-filter-branch
ます。
削除するprivate.txt
パスワードなどをリストしたファイルを作成し(1行に1エントリ)、次のコマンドを実行します。
$ java -jar bfg.jar --replace-text private.txt my-repo.git
リポジトリの履歴のしきい値サイズ(デフォルトでは1 MB)未満のすべてのファイルがスキャンされ、一致する文字列(最新のコミットにないもの)は文字列 "*** REMOVED ***"に置き換えられます。次に、を使用git gc
して、死んだデータを削除できます。
$ git gc --prune=now --aggressive
BFGは通常、実行よりも10〜50倍高速でgit-filter-branch
、オプションは簡素化され、次の2つの一般的なユースケースに合わせて調整されます。
完全な開示:私はBFG Repo-Cleanerの作成者です。
git commit
。それ以外の場合は、開発者のツールボックスの新しいツールの+1 :)
These are your protected commits, and so their contents will NOT be altered
、残りのコミット履歴を調べて修正している間、最後のコミットを明示的に報告します。ただし、ロールバックする必要がある場合は、ロールバック***REMOVED***
したコミットで検索を実行する必要があります。
GitHubにプッシュした場合、強制プッシュでは不十分です。リポジトリを削除するか、サポートにお問い合わせください
1秒後に強制プッシュしても、以下で説明するように十分ではありません。
唯一の有効な行動方針は次のとおりです。
パスワードのような変更可能な認証情報が漏洩したものは何ですか?
いいえ(裸の写真):
リポジトリ内のすべての問題が削除されるかどうかを気にしますか?
はい:
次の理由により、強制的に1秒後に押すだけでは不十分です。
GitHubは、未解決のコミットを長期間保持します。
ただし、GitHubのスタッフは、このようなぶら下がりコミットに連絡した場合、それらを削除する権限を持っています。
すべてのGitHubコミットメールをレポにアップロードしたときにこれを体験したので、削除するように求められたので、削除しましたgc
。ただし、データが含まれているプルリクエストは削除する必要があります。これにより、最初の削除から最大1年後までレポデータにアクセスできます。
ぶら下がりコミットは、次のいずれかで確認できます。
コミット時にソースを取得する1つの便利な方法は、ダウンロードzipメソッドを使用することです。これは、任意の参照を受け入れることができます。例:https : //github.com/cirosantilli/myrepo/archive/SHA.zip
次のいずれかの方法で、不足しているSHAをフェッチできます。
type": "PushEvent"
。例:鉱山:https : //api.github.com/users/cirosantilli/events/public(Wayback machine)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
このスクリプトをお勧めしますDavid Underhillによるします。私にとっては魅力のように機能しました。
natacadoのフィルターブランチにこれらのコマンドを追加して、残された混乱をクリーンアップします。
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
完全な脚本(すべてはDavid Underhillの功績です)
#!/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
git gc --aggressive --prune=now
明確にするために:受け入れられた答えは正しいです。まずお試しください。ただし、一部のユースケースでは、特に「致命的:不正なリビジョン--prune-empty」などの不愉快なエラーが発生した場合や、リポジトリの履歴を気にしない場合は、不必要に複雑になる可能性があります。
別の方法は次のとおりです。
もちろん、これによりすべてのコミット履歴ブランチと、githubリポジトリとローカルgitリポジトリの両方から問題が削除されます。これが受け入れられない場合は、別の方法を使用する必要があります。
これを核オプションと呼んでください。
使用できますgit forget-blob
。
使い方はかなり簡単git forget-blob file-to-forget
です。あなたはここでより多くの情報を得ることができます
履歴、reflog、タグなどのすべてのコミットから消えます
私は時々同じ問題に遭遇し、この投稿や他の記事に戻る必要があるたびに、プロセスを自動化したのはそのためです。
これをまとめることができたスタックオーバーフローからの貢献者へのクレジット
フィルターブランチを使用する:
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
私はこれまで数回これをしなければなりませんでした。これは一度に1つのファイルでのみ機能することに注意してください。
ファイルを変更したすべてのコミットのリストを取得します。一番下のものが最初のコミットになります:
git log --pretty=oneline --branches -- pathToFile
履歴からファイルを削除するには、最初のcommit sha1と前のコマンドからのファイルへのパスを使用し、これらをこのコマンドに入力します。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..
私のandroidプロジェクトでは、admob_keys.xmlをapp / src / main / res / values /フォルダーに分離された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