3

を使用して、履歴から多数の大きなファイルを削除しようとしていますfilter-branch。以前にこのコマンドを使用して成功したことがありますが、現在、特定のエッジ ケースで問題が発生しています。

問題は、これらの大きなファイルが実際には削除されず、同じパスを持つ小さなバージョンに置き換えられたことです。

私が知る限り、私には独特の問題があると思います。

Git ログ

詳しく説明すると、私のレポの基本的な表現は次のとおりです。

----- A ------ B ----------- HEAD

どこ:

A is the commit where the large files were introduced
B is the commit (about 30 later) where the large files were replaced with smaller ones
HEAD is thousands of commits forward of B (~2 years of active development)

Git フィルターブランチ

理論的には、次のようなことができるはずです。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' <parent of A>..B 

包括的ではない<parent of A>ため、使用する必要があると思います。filter-branch(Bの親も使用する必要があるかどうかはわかりませんが、これは今のところ私の心配の中で最も少ないです)。

これを実行すると、次のエラーが表示されます。

$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' <parent of A>..B 
Which ref do you want to rewrite?

だから私--glob="refs/heads/master*"はトリックを行うように見えるコマンドの最後に含めました(source)。

実行が完了すると、ファイルは完全に削除されました - git は私が指定した上限を無視しているようです。

それで、この方法が可能かどうか疑問に思っていますか?

代替アプローチ

潜在的な答えが問題の解決に集中できるように、私が持っていた他のいくつかのアイデアをリストする必要があると思いました.

  1. 実用的なアプローチは、ファイル名の変更を HEAD でコミットしてから実行することgit filter-branch ... HEADです。ただし、私のリポジトリには活発な開発中のブランチが多数あり、この方法は非常に面倒だと思います。
  2. もう 1 つの方法は、ここで説明されているようなことを行うことです。引用するには:create a temporary branch to point at HEAD^, filter-branch it, then add a graft to stitch the remaining commit on top of it, then filter-branch HEAD and then remove the graft.

誰かが以前にこの問題に遭遇し、専門知識を貸してくれることを願っています。

アップデート

削除したいファイルの合計は500MBに達するので、当然のことながら削除したいと思っています。これらは、私が入社するずっと前にコミットされたもので、社内の Mercurial サーバーから GitHub への移行の名残です (500MB を社内サーバーにプッシュすることは、GitHub よりも目立たないと思います...)。

更新 2

私はtwalbergの2番目の回答に従っています(正しい方法で使用していると思います):

git filter-branch --index-filter '(( $(git rev-list <SHA-of-child-of-B> --not $GIT_COMMIT | wc -l) > 0 )) && git rm --cached --ignore-unmatch <filenames>' 

これにより、私が期待するような出力が生成されます。

...
Rewrite dc8a4b29463bfa43c2f3efe0c6e5a29a5cc6e0ef (1071/5680)rm 'file1'
rm 'file2'
rm 'file3'
rm 'file4'
...

(予期された?) エラーで終了する前に:

Rewrite e6b712b57257e2edd0bb9fbbac59e4c9d7b5aa79 (1072/5680)index filter failed: (( $(git rev-list e6b712b --not $GIT_COMMIT | wc -l) > 0 )) && git rm -rf --ignore-unmatch <filename>

e6b712bの子はどこですかB

この時点で、すべてが機能していると思いますので、リポジトリのローカル ファイルシステム クローンを作成してテストします。

git clone file://<repo> <new repo>

オブジェクトの数とパックファイルのサイズがごくわずかに減少しました。理由はわかりません。git count-objects -v元のリポジトリとそれに対して実行されたリポジトリに対して実行することにより、次のfilter-branchようになります。

元のリポジトリ:

count: 0
size: 0
in-pack: 106640
packs: 1
size-pack: 815512
prune-packable: 0
garbage: 0

filter-branched およびファイルシステムの複製されたリポジトリ:

count: 0
size: 0
in-pack: 96165
packs: 1
size-pack: 793656
prune-packable: 0
garbage: 0

なぜこれがまだうまくいかないのか本当にわかりません - おそらく私は提案された答えに正しく従っていませんか?

4

2 に答える 2

1

残念ながら、リポジトリからこれらのオブジェクトを本当に削除したい場合 (現在および将来のリビジョンから単純に削除するのではなく)filter-branchがその方法ですAAコミットのコミット ハッシュはそのコミットのすべての親のコミット ハッシュに依存するため、その履歴に含まれる内容も書き換える必要があります。を含むすべてのブランチを書き換えない場合A、それらのオブジェクトは到達可能な履歴の一部のコミットの一部であり、プルーニングされません。

その履歴にBR含まれる各ブランチに対して、これは機能するはずです:A

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' BR --not A~1

これは、( s 親Aでブランチを剪定することによって) from から現在のブランチの先端に書き直されます。ただし、新しい小さなバージョンに置き換えられた後でも、これらすべてのコミットからファイルが削除されます。commit までのみを削除するには、次のようにフィルター スクリプトを展開します。ABRB

... --index-filter '(( $(git rev-list <SHA-of-child-of-B> --not $GIT_COMMIT | wc -l) > 0 )) && git rm ...' ...

これは rev-list を使用して、現在書き換え中のコミットから の子までのすべてのリビジョンを一覧表示し、Bそれらの行を数え、git rm1 つ以上のリビジョンがその範囲にある場合にのみ実行します ( の場合$GIT_COMMIT == B、1 行が出力されます。したがって、の子を使用する必要がありますB)。

これは、単一のブランチであってもかなり大きな変更であり、 で生成されたブランチが多数ある場合は多くの作業が必要Aになるため、最終的にそれが価値があるかどうか、またはより大きなディスクが必要なだけかどうかを判断する必要があります (これらのファイルの大きさについては正確には言及していません)。

于 2013-02-12T17:22:42.387 に答える
0
A     is the commit where the large files were introduced
B     is the commit (about 30 later) where the large files were replaced 
      with smaller ones
HEAD  is thousands of commits forward of B (~2 years of active development)

これを言ったfilter-branchので、2年分のコミットSHAを書き換えると思うので、強くお勧めします。おそらく別の解決策はgit revert

git revert SHA_A..SHA_B
    Revert the changes done by commits from commit SHA_A (included) to
    SHA_B (included)
于 2013-02-12T16:41:00.047 に答える