web-dev-qa-db-ja.com

git履歴内のファイルからテキストを置き換える方法は?

私は常にインターフェースベースのgitクライアント(smartGit)を使用しているため、gitコンソールの経験はあまりありません。

ただし、履歴からすべての.txtファイルの文字列を置き換える必要があります(したがって、ファイル全体を消去するのではなく、文字列を置き換えるだけです)。次のコマンドが見つかりました。

git filter-branch --tree-filter 'git ls-files -z "*.php" |xargs -0 Perl -p -i -e "s#(PASSWORD1|PASSWORD2|PASSWORD3)#xXxXxXxXxXx#g"' -- --all

これを試してみましたが、残念ながら、パスワードは変更されましたが、すべてのバイナリファイルが破損していることに気付きました。画像等はすべて破損します。

バイナリファイルを破損しない、これを行うためのより良い方法はありますか?

ありがとう。

編集:

私は何かと混同しました。バイナリファイルが破損する原因となった実際のコードは次のとおりです。

$ git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/originalpassword/newpassword/g' {} \;"

一番上のコードは実際に削除されました私のパスワードを持つすべてのファイルは奇妙なことに十分です。

37
Tom

-name "pattern"findに渡すことで、不要なファイルに触れることを回避できます。

これは私のために働きます:

git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
    's/originalpassword/newpassword/g' {} \;"
37
jweyrich

BFG Repo-Cleaner を使用することをお勧めします。これは、Git履歴からファイルを書き換えるために特別に設計されたgit-filter-branchのよりシンプルで高速な代替手段です。

ここでは、次の手順を慎重に実行する必要があります。 https://rtyley.github.io/bfg-repo-cleaner/#usage -ただし、コアビットはこれだけです。 BFGのjarファイルをダウンロードしてください) (Java 7以上が必要))そして次のコマンドを実行します:

$ Java -jar bfg.jar  --replace-text replacements.txt -fi *.php  my-repo.git

replacements.txtファイルには、実行するすべての置換が次のような形式で含まれている必要があります(1行に1つのエントリ-コメントは含めないでください)。

PASSWORD1 # Replace literal string 'PASSWORD1' with '***REMOVED***' (default)
PASSWORD2==>examplePass         # replace with 'examplePass' instead
PASSWORD3==>                    # replace with the empty string
regex:password=\w+==>password=  # Replace, using a regex
regex:\r(\n)==>$1               # Replace Windows newlines with Unix newlines

リポジトリ履歴全体がスキャンされ、.phpファイル(サイズが1MB未満)で置換が実行されます:一致する文字列(latestcommit)が置き換えられます。

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

85
Roberto Tyley

/usr/local/git/findsed.shに、次の内容のファイルを作成しました。

find . -name 'githubDirToSubmodule.sh' -exec sed -i '' -e 's/What I want to remove//g' {} \;

コマンドを実行しました:

git filter-branch --tree-filter "sh /usr/local/git/findsed.sh"

コマンドの説明

Git filter-branchを実行すると、これまでにコミットした各リビジョンが1つずつ実行されます。 --tree-filterは、コミットされたリビジョンごとにfindsed.shスクリプトを実行して保存し、次のリビジョンに進みます。

Findコマンドは、特定のファイルまたはファイルのセットを検索し、そのファイルに対してsedエディターを実行(-exec)します。 sedは、s /の後に正規表現を取り、それを/と/ gの間の文字列(私の例では空白)に置き換えるコマンドです。 {}は、findコマンドによって指定されたファイルパスへの参照です。ファイルパスはsedに送られるので、sedは何を処理するかを認識します。 \; -execコマンドを終了するだけです。

シェルスクリプトとコマンドを別々の部分に分離することで、引用符 ''または ""に関して複雑さが軽減されます。

特性

私はこれをMacに正常に実装しましたが、明らかにsedはMacの特定の(古い?)バージョンです。動作が異なる場合があるため、これは重要です。必ずsed-i ''を実行してください。そうしないと、ファイルの末尾に「-e」が追加され、バックアップファイルに名前を付けたいと思っていました。 -i ''は、バックアップファイルを作成しないでください。ファイルをその場で編集するだけで、バックアップファイルは必要ありません。

-name'filename.sh 'を指定すると、解決できない別の問題を回避するのに役立ちました。 .shを含む別のファイルがあり、そのファイルは改行文字なしで終了しました。 sedは、「s/blah/blah/g」がそのファイル内の何にも一致しないにもかかわらず、何らかの理由で末尾に改行文字を追加します。そのため、その問題を理解する代わりに、他のすべてのファイルを無視するように検索に指示しました。

機能する追加コマンド

さらに、これらのコマンドがfindsed.shファイルで機能することがわかりました(一度に1つのコマンドのみで、複数ではないため、他のコマンドをコメントアウトしてください)。

find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;

楽しい!

6
Nay

Git 2.24(2019年第4四半期)では、 git filter-branch(およびBFG)は非推奨になりました

同等のものは、 newren/git-filter-repo を使用し、その セクションの例

cd repo
git filter-repo --path-glob '*.txt' --replace-text expressions.txt

expressions.txt

literal:originalpassword==>newpassword
2
VonC

シェル拡張の問題である可能性があります。 filter-branchがコマンドを評価するまでに"*.php"の前後の引用符を失っている場合は、何も展開されていない可能性があるため、git ls-files -zはすべてのファイルを一覧表示します。

フィルタブランチのソースを確認したり、さまざまな引用のトリックを試したりすることもできますが、私が行うのは、ツリーフィルタを実行する1行のシェルスクリプトを作成し、代わりにそのスクリプトを渡すことです。

2
Ben Jackson