web-dev-qa-db-ja.com

Git履歴から機密ファイルとそのコミットを削除する

GitプロジェクトをGitHubに配置したいのですが、機密データ(ユーザー名とパスワード、capistranoの/config/deploy.rbなど)を含む特定のファイルが含まれています。

これらのファイル名を。gitignoreに追加できることは知っていますが、Git内の履歴は削除されません。

また、/。gitディレクトリを削除して最初からやり直したくありません。

Git履歴で特定のファイルのallトレースを削除する方法はありますか?

310
Stefan

すべての実用的な目的のために、最初に心配する必要があることはパスワードの変更です! 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 manpage の「UPSREAM REBASEからの復旧」の手順に従う必要があります。


将来、機密情報を含むいくつかの変更を誤ってコミットしたが、beforeがリモートリポジトリにプッシュされることに気付いた場合、いくつかの簡単な修正があります。最後のコミットが機密情報を追加するものである場合、単に機密情報を削除してから実行できます:

git commit -a --amend

これにより、git rmで行われたファイル全体の削除を含む、行った新しい変更で以前のコミットが修正されます。変更が履歴にさかのぼっても、まだリモートリポジトリにプッシュされていない場合は、インタラクティブなリベースを実行できます。

git rebase -i Origin/master

これにより、リモートリポジトリを使用した最後の共通の祖先以降に行ったコミットでエディタが開きます。機密情報を含むコミットを表す行の「選択」を「編集」に変更し、保存して終了します。 Gitは変更を順を追って説明し、次のことができる場所に移動します。

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

機密情報を含む変更ごと。最終的には、ブランチに戻り、新しい変更を安全にプッシュできます。

394
natacado

パスワードを変更することは良い考えですが、レポジトリの履歴からパスワードを削除するプロセスには、Gitからプライベートデータを削除するために明示的に設計されたgit-filter-branchのより高速でシンプルな代替手段である BFG Repo-Cleaner をお勧めしますリポジトリ.

削除するパスワードなどをリストしたprivate.txtファイルを作成し(1行に1エントリ)、次のコマンドを実行します。

$ Java -jar bfg.jar  --replace-text private.txt  my-repo.git

レポジトリの履歴内のしきい値サイズ(デフォルトでは1MB)未満のすべてのファイルがスキャンされ、一致する文字列(latestコミットにない)がすべて置き換えられます文字列「***削除済み***」。その後、git gcを使用して、デッドデータを削除できます。

$ git gc --Prune=now --aggressive

通常、BFGはgit-filter-branchを実行するよりも10〜50倍高速であり、これらの2つの一般的なユースケースに合わせてオプションが簡素化および調整されています。

  • 削除Crazy Big Files
  • パスワード、クレデンシャルおよびその他プライベートデータの削除

完全な開示:私はBFGリポジトリクリーナーの作成者です。

79
Roberto Tyley

このスクリプト 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
[email protected]
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
18
Jason Goemaat

GitHubにプッシュした場合、1秒後に強制的にプッシュしても遅すぎます

これをテストするために、レポジトリを作成しました: https://github.com/cirosantilli/test-dangling そして完了:

git init
git remote add Origin [email protected]: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

ただし、リポジトリを削除した場合、APIからすぐにコミットが消え、404が返されます。 https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 これは、同じ名前の別のリポジトリを再作成しても機能します。

だから私の推奨される行動方針は:

  • 資格情報を変更する

  • それだけでは不十分な場合(裸の写真など):

    • 貴重な問題データはありますか?

      • no:リポジトリを削除します
      • はい:サポートに連絡してください

明確にするために:受け入れられた答えは正しいです。まず試してみてください。ただし、一部のユースケースでは不必要に複雑になる場合があります。特に、 'fatal:bad revision --Prune-empty'などの不快なエラーが発生した場合、またはレポの履歴を実際に気にしない場合です。

代替手段は次のとおりです。

  1. プロジェクトのベースブランチにcd
  2. 機密コード/ファイルを削除します
  3. rm -rf .git /#コードからすべてのgit情報を削除します
  4. Githubに移動して、リポジトリを削除します
  5. このガイドに従って、通常どおりにコードを新しいリポジトリにプッシュします- https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command- line /

もちろん、これにより、すべてのコミット履歴ブランチ、およびgithubリポジトリとローカルgitリポジトリの両方から問題が削除されます。これが受け入れられない場合は、別のアプローチを使用する必要があります。

これを核オプションと呼びます。

9
lostphilosopher

ここにWindowsでの私のソリューションがあります

git filter-branch --tree-filter "rm -f 'filedir/filename'" HEAD

git Push --force

パスが正しいことを確認してください。そうでない場合は機能しません

私はそれが役立つことを願っています

7
vertigo71

filter-branchを使用します。

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。詳細はこちらで入手できます

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

履歴、reflog、タグなどのすべてのコミットから消えます

私は時々同じ問題に遭遇し、この投稿や他の記事に戻る必要があるたびに、プロセスを自動化しました。

これをまとめることができたStack Overflowの貢献者へのクレジット

5
nachoparker

これまでにこれを数回やらなければなりませんでした。これは一度に1つのファイルに対してのみ機能することに注意してください。

  1. ファイルを変更したすべてのコミットのリストを取得します。一番下のものが最初のコミットになります:

    git log --pretty=oneline --branches -- pathToFile

  2. 履歴からファイルを削除するには、最初のコミットsha1と前のコマンドからのファイルへのパスを使用し、これらをこのコマンドに入力します。

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..

3
b01

そのため、次のようになります。

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

Gitから追跡ファイルのキャッシュを削除し、そのファイルを.gitignoreリストに追加します

3
przbadu

Androidプロジェクトでは、admob_keys.xmlapp/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
1
Ercan Duman