Git Filter-Repoは、履歴を書き換えるための汎用性の高いツールです。これには、他のどこにも見つけられない機能が含まれます。 Gitフィルターブランチと同じツールの空間に陥りますが、能力がはるかに多く、些細な書き換えのケースを超えてユーザビリティをスケーリングするデザインを備えた、降伏を誘発するパフォーマンスが低下することはありません。 GitフィルターRepoは、Gitフィルターブランチの代わりにGitプロジェクトで推奨されています。
ほとんどのユーザーは、おそらくフィルターRepoを単純なコマンドラインツールとして使用するだけですが(おそらくそのフラグのいくつかのみを使用する可能性が高い)、そのコアフィルターRepoには履歴書き換えツールを作成するためのライブラリが含まれています。そのため、専門的なニーズを持つユーザーは、それを活用して、まったく新しい履歴書き換えツールをすばやく作成できます。
Filter-Repoには次のことが必要です。
git-filter-repo
単一ファイルのPythonスクリプトであり、多くのシステムで基本的に使用するためのインストールを行うために行われました。そのファイルを$パスに配置するだけです。
基本的な使用法または特別なケースを超えたものについては、install.mdを参照してください。次のいずれかが適用される場合にのみ、より複雑な指示が必要です。
包括的なドキュメントについて:
例から学ぶことを好む場合:
これについては、フィルターRepoに関するGit Rev Newsの記事で詳しく説明しましたが、主要な競合他社のハイライトがいくつかあります。
フィルターブランチは、自明でないリポジトリの場合、非常に遅く(本来あるべきよりも数桁遅くなる)非常に遅くなっています。
フィルターブランチには、あなたの書き直しが静かに腐敗したり、少なくともあなたが始めたものよりも問題があり乱雑なものを与えて、「クリーンアップ」の努力を妨げることができるゴッチャスがいっぱいになります。
フィルターブランチは、わずかに非自明でさえも書き直しに使用するのが非常に面倒です。
GITプロジェクトは、フィルターブランチに関する上記の問題を互換性のあるものに修正することはできないと述べています。彼らは、あなたがフィルターブランチの使用をやめることをお勧めします
フィルターブランチの頑固なファンは、よりパフォーマンスのあるフィルターレポに基づいたフィルターブランチの再実装であるフィルターレーミング(別名フィルターブランチイッシュ)に興味があるかもしれません(ただし、フィルターほど速くまたは安全ではありませんが - レポ)。
フィルターブランチのマニュアルからフィルターREPOコマンドにサンプルコマンドを変換する方法を示すチートシートが利用可能です。
当時の素晴らしいツールでしたが、いくつかのものをシンプルにしますが、いくつかの種類の書き直しに限定されています。
そのアーキテクチャは、より多くの種類の書き換えを処理することに適していません。
そのアーキテクチャは、意図したユーザーケースでもいくつかの欠点とバグを提示します。
BFGのファンは、BFG-Repoに基づいたBFGの再実装であるBFG-Ishに興味があるかもしれません。
BFGレポクリーナーのマニュアルからフィルターREPOコマンドにサンプルコマンドを変換する方法を示すチートシートが利用可能です。
そのピースを他のより大きなレポに統合することを目的として、リポジトリの一部を抽出したいとしましょう。抽出のために、次のようにしたいと思います。
フィルターRepoでこれを行うことは、次のコマンドと同じくらい簡単です。
git filter-repo --path src/ --to-subdirectory-filter my-module --tag-rename ' ' : ' my-module- '
(単一の引用は不要ですが、 my-module-
でプレフィックスとして空の文字列を置き換えていることを人間に明確にします - )
BFGレポクリーナーは、この種の書き換えができません。実際、3種類の募集変更はすべて、その機能の範囲外です。
フィルターブランチには、必要な呼び出しを把握しても、警告の山(以下の詳細)が付属しています。
git filter-branch
--tree-filter ' mkdir -p my-module &&
git ls-files
| grep -v ^src/
| xargs git rm -f -q &&
ls -d *
| grep -v my-module
| xargs -I files mv files my-module/ '
--tag-name-filter ' echo "my-module-$(cat)" '
--prune-empty -- --all
git clone file:// $( pwd ) newcopy
cd newcopy
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git gc --prune=now
上記のフィルターブランチの呼び出しが、Tree-filterを使用するために非常に遅いことに気付く人もいるかもしれません。代わりに、フィルターブランチの-index-filterオプションを使用して、上記のコマンドを以下に変更できます。
git filter-branch
--index-filter ' git ls-files
| grep -v ^src/
| xargs git rm -q --cached;
git ls-files -s
| sed "s%$(printf \t)%&my-module/%"
| git update-index --index-info;
git ls-files
| grep -v ^my-module/
| xargs git rm -q --cached '
--tag-name-filter ' echo "my-module-$(cat)" '
--prune-empty -- --all
git clone file:// $( pwd ) newcopy
cd newcopy
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git gc --prune=now
ただし、いずれかのフィルターブランチコマンドには、警告の山があります。まず、フィルターブランチのためにここに5つのコマンドをリストする理由を疑問に思う人もいるかもしれません。クローンが古いオブジェクトを取り除くのに十分であると主張している-allおよび-tag-name-filter、およびフィルターブランチのマンページの使用にもかかわらず、他のタグを削除して別のGCを実行するための追加の手順はまだ必要です古いオブジェクトをきれいにし、どこかを押す前に新しい歴史と古い歴史を混ぜないでください。その他の警告:
次のようなものと一緒にこれをハッキングすることができます。
git fast-export --no-data --reencode=yes --mark-tags --fake-missing-tagger
--signed-tags=strip --tag-of-filtered-object=rewrite --all
| grep -vP ' ^M [0-9]+ [0-9a-f]+ (?!src/) '
| grep -vP ' ^D (?!src/) '
| perl -pe ' s%^(M [0-9]+ [0-9a-f]+ )(.*)$%1my-module/2% '
| perl -pe ' s%^(D )(.*)$%1my-module/2% '
| perl -pe s%refs/tags/%refs/tags/my-module-%
| git -c core.ignorecase=false fast-import --date-format=raw-permissive
--force --quiet
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git reset --hard
git reflog expire --expire=now --all
git gc --prune=now
しかし、これにはいくつかの厄介な警告と制限があります。
既存のリポジトリフィルタリングツールはいずれも、私が望んでいたことをしませんでした。彼らは皆、私のニーズのために不足していました。以下の最初の8つの特性のいずれかを提供したツールはありません。また、最後の4つの特性のうち2つ以上を提供するツールはありません。
[レポートの開始]ユーザーにリポジトリの分析を提供して、他のツールを推測したり見つけたりすることを期待するのではなく、剪定または名前を変更するものを開始するのに役立ちます。 (例えば、例えば、-Analyzeなどの特別なフラグを使用して初めて実行することによって。)
[削除]を使用するだけでなく、ユーザーが選択したパスを簡単に削除する方法を提供する代わりに、ユーザーが特定のパスのみを維持するためのフラグを提供します。確かに、ユーザーは、保持したいパス以外のすべてのパスを削除するように指定することでこれを回避できますが、リポジトリのあらゆるバージョンに存在していたすべてのパスを指定する必要性は、非常に痛みを伴う場合があります。フィルターブランチの場合、 git ls-files | grep -v ... | xargs -r git rm
などのパイプラインを使用してくださいgit ls-files | grep -v ... | xargs -r git rm
合理的な回避策かもしれませんが、扱いにくく、ユーザーにとってはそれほど簡単ではありません。さらに、これらのコマンドはしばしば動作しているシステム固有です(私が提供したスニペットでGnuismを見つけることができますか?)。
[改名]パスの名前を変更するのは簡単です。たとえば、サブディレクトリをリポジトリのルートとして扱うことを許可することに加えて、ユーザーがリポジトリのルートをサブディレクトリにするためのオプションも提供します。そして、より一般的には、ファイルとディレクトリを簡単に変更できるようにします。名前を変更すると同じパスに複数のファイルが存在するかどうかが正気のチェックを提供します。 (そして、コミットが変更なしでoldname-> newNameをコピーするだけの場合、oldname-> newNameをフィルタリングするだけで、そのコミットで正気チェックをトリガーして死ぬように特別な取り扱いを追加します。)
[よりインテリジェントな安全性]リポジトリ内の特別な名前空間への元のRefのコピーを書くことは、ユーザーフレンドリーな回復メカニズムを提供しません。多くはそれを使って回復するのに苦労するでしょう。リポジトリフィルタリング操作を行ったことがあるほとんどすべての人が、エラーの場合にクローンを拭き取ることが非常に簡単な回復メカニズムであるため、新鮮なクローンでそうしました。ユーザーが - フォースでオーバーライドしない限り、新鮮なクローンにない場合は、検出および保釈することにより、ワークフローを強くお勧めします。
[Auto Shrink]古いCruftを自動的に削除し、フィルタリング後にユーザーのリポジトリを再梱包します(オーバーライドしない限り)。これにより、ユーザーの物事が簡素化され、古い歴史と新しい歴史の混合を避けるのに役立ち、マンページで文書化されたレポを縮小するためのマルチステッププロセスが実際には機能しない場合があります。 (私はあなたを見ています、フィルターブランチ。)
[きれいな分離]古いリポジトリを混合し、リポジトリを組み合わせて書き直したため、ユーザーを混乱させない(そして古いものの偶発的な再プッシングを防ぐ)。 (これは、-tag-name-filterオプションを使用する場合のフィルターブランチの問題であり、ブランチのサブセットのみをフィルタリングする場合にも問題になる場合があります。)
[汎用性]ユーザーにツールを拡張したり、既存の機能を活用する新しいツールを作成したり、(a)個別のプロセスをフォークする必要性(パフォーマンスを破壊する)を回避する方法でこの拡張性を提供する機能を提供します。ユーザーがOS依存のシェルコマンドを指定させることを避けます(ユーザーが相互にコマンドを共有できないようにします)、(c)リッチデータ構造を利用します(ハッシュ、DICT、リスト、および配列はシェルでは非常に困難です)、( d)合理的な文字列操作機能(シェルが非常に不足している)を提供します。
[古いコミット参照]は、ユーザーが新しいリポジトリを使用して古いコミットIDを使用する方法を提供します(特に、ref/置換/参照を使用して古いハッシュから新しいハッシュまでのマッピングを介して)。
[メッセージメッセージの一貫性をコミット] IDで他のコミットを指す場合(例:「これはコミット01234567890ABCDEF」、「コミット0013DEADBEEF9A ...」)、新しいコミットIDを参照するために書き直される必要があります。
[空の剪定になる]フィルタリングのために空になることは剪定する必要があります。コミットの親が剪定されている場合、最初の非プルーニックの祖先は新しい親になる必要があります。非プルーニックの祖先が存在せず、コミットがマージではなかった場合、それは新しいルートコミットになります。プルーニック以外の祖先が存在し、コミットがマージであった場合、マージは1つの親を持つことができます(したがって、それ自体のファイルの変更がない場合にそれ自体が剪定される非マージなコミットになる可能性があります) 。ここで注意すべき特別なことの1つは、私たちが空になることではなく、空になることではなく、剪定することです。一部のプロジェクトは、バージョンの理由や公開の理由で意図的に空のコミットを作成しますが、これらは削除されるべきではありません。 (特別なケースとして、空に始まったが、その親が剪定されたこともコミットします。また、「空になる」と見なされます。)
[劣化する剪定になる]空になるコミットの剪定は、トポロジーの変化を引き起こす可能性があり、多くの特別なケースがあります。通常、グラフトポロジを保持するために必要なため、マージのコミットは削除されませんが、両親や他の祖先の剪定により、最終的には1人以上の親が失われる可能性があります。単純なケースはすでに上記で記録されています。マージのコミットでは、非マージなコミットになるのに十分な親を失い、ファイルの変更がない場合、それも剪定することができます。マージコミットは、退化するトポロジも持つことができます。それは両方の親として機能するMerge_Baseで終わる可能性があります(元のリポジトリからのすべての介入コミットが剪定された場合)。親。そのような場合、マージに独自のファイルの変更がない場合、マージのコミットも剪定することができます。ただし、空の剪定と同様に、退化し始めた(-no-ffの合併など、意図的である可能性があることを示す)が、退化し、ファイルの変更がないマージコミットのみが縮退したことを剪定することはありません。彼ら自身。
[速度]フィルタリングはかなり高速でなければなりません
貢献ガイドラインを参照してください。
フィルターREPOコミュニティの参加者は、GITプロジェクトと同じ基準を順守することが期待されるため、GIT行動規範が適用されます。
フィルターREPOとその前身での作業は、フィルターREPOがその仕事をするために必要なことに基づいて、コアGITの高速エクスポートと高速輸入(および時には他のコマンド)の多数の改善を推進しています。