22

git過去にバイナリ テスト ファイルと Java ファイルが含まれていたため、管理できないサイズに成長したリポジトリが多数あり.jarます。

これらのリポジトリをgit filter-branching し、それらが使用されているすべての場所 (リポジトリによってはそれぞれ数十から数百のデプロイメント) で再クローンを作成し、履歴の書き換えに関する問題があるかどうか疑問に思っていました。その他のソリューション。

理想的には、各リポジトリの履歴を書き換えずに、問題のあるファイルを外部化したいと考えています。理論的には、同じファイルを同じサイズと同じハッシュでチェックアウトし、別の場所 (ローカル オブジェクト ストアではなくリモート) からそれらを調達しているため、これは可能であるはずです。悲しいかな、これまでに見つけた潜在的な解決策のどれも、これを可能にしているようには見えません。

git-annexから始めて、私の問題の解決策に最も近いのはHow to retroactively annex a file already in a git repoでしたが、大きなファイルを削除するだけの場合と同様に、変換するには履歴を書き直す必要がありますオリジナルgit addを にgit annex add

そこから進んで、 git -annex ではないものにリストされている他のプロジェクトを調べ始めたので、 git-bigfilesgit-media、およびgit-fatを調べました。残念ながら、私たちは のgit-bigfilesフォークを使用できません。gitなぜなら、私たちは Eclipseショップgitであり、とEGitを混合して使用しているためです。既存の大きなファイルを外部の同等のものに置き換えることはできますが、既存の大きなファイルを削除するために履歴を書き直す必要があるため、git-mediaまたはgit-fatが私が望むことを実行できるようには見えません。コミットされています。

git filter-branchでは、履歴を書き換えずに .git リポジトリをスリム化することは可能でしょうか?それとも、再デプロイの負荷全体を使用する計画に戻るべきでしょうか?


余談ですが、これ可能であると信じていますが、おそらくgit現在の浅いクローンの実装と同じ制限に関連付けられています。

Git は、同じ BLOB に対して複数の可能な場所を既にサポートしています。これは、特定の BLOB がルース オブジェクト ストア( .git/objects) またはパック ファイルgit-annex(.git/objects) にある可能性があるため、理論的には、そのレベルでフックされるようなものが必要になるだけです。上位ではなく (つまり、必要に応じてオンデマンドのリモート BLOBをダウンロードするという概念があります)。残念ながら、このようなことを実装したり、提案したりする人を見つけることができません。

4

4 に答える 4

11

並べ替え。Git の置換機能を使用して、肥大化した履歴を脇に置いて、必要な場合にのみダウンロードされるようにすることができます。浅いクローンのようなものですが、浅いクローンの制限はありません。

アイデアは、新しいルート コミットを作成してブランチを再起動し、古いブランチのヒント コミットを選択するというものです。通常、この方法ではすべての履歴が失われます (これは、これらの大きなファイルのクローンを作成する必要がないことも意味し.jarます) が、履歴が必要な場合は、履歴コミットをフェッチし、git replaceそれらをシームレスにつなぎ合わせるために使用できます。

詳細な説明とウォークスルーについては、Scott Chacon の優れたブログ投稿を参照してください。

このアプローチの利点:

  • 履歴は変更されません。.jars大きくてすべてが揃った古いコミットに戻る必要がある場合でも、それは可能です。
  • 古い履歴を参照する必要がない場合、ローカル クローンのサイズは適切で小さく、作成した新しいクローンではほとんど役に立たない大量のデータをダウンロードする必要はありません。

このアプローチの欠点:

  • デフォルトでは、完全な履歴は利用できません。ユーザーは、履歴を取得するためにいくつかの手順を踏む必要があります。
  • 履歴に頻繁にアクセスする必要がある場合は、肥大化したコミットをダウンロードすることになります。
  • このアプローチには、履歴の書き換えと同じ問題がいくつか残っています。たとえば、新しいリポジトリが次のようになっているとします。

    * modify bar (master)
    |
    * modify foo  <--replace-->  * modify foo (historical/master)
    |                            |
    * instructions               * remove all of the big .jar files
                                 |
                                 * add another jar
                                 |
                                 * modify a jar
                                 |
    

    そして、誰かが歴史的なブランチから離れた古いブランチを持っていて、それらがマージされます:

    * merge feature xyz into master (master)
    |\__________________________
    |                           \
    * modify bar                 * add feature xyz
    |                            |
    * modify foo  <--replace-->  * modify foo (historical/master)
    |                            |
    * instructions               * remove all of the big .jar files
                                 |
                                 * add another jar
                                 |
                                 * modify a jar
                                 |
    

    その後、大きな履歴コミットがメイン リポジトリに再び表示され、最初の場所に戻ります。これは、履歴を書き換えるよりも悪いことではないことに注意してください。誰かが誤って書き換え前のコミットにマージする可能性があります。

    updateこれは、共有リポジトリにフックを追加して、過去のルート コミットを再導入するプッシュを拒否することで軽減できます。

于 2013-07-12T19:53:45.543 に答える
8

No, that is not possible – You will have to rewrite history. But here are some pointers for that:

  • As VonC mentioned: If it fits your scenario, use BFG- repo cleaner – it’s a lot easier to use than git filter-branch.
  • You do not need to clone again! Just run these commands instead of git pull and you will be fine (replace origin and master with your remote and branch):

    git fetch origin
    git reset --hard origin/master
    

    But note that unlike git pull, you will loose all the local changes that are not pushed to the server yet.

  • It helps a lot if you (or somebody else in you team) fully understand how git sees history, and what git pull, git merge and git rebase (also as git rebase --onto) do. Then give everybody involved a quick training on how to handle this rewrite situation (5-10 mins should be enough, the basic dos and don’ts).
  • Be aware that git filter-branch does not cause any harm in itself, but causes a lot of standard workflows to cause harm. If people don’t act accordingly and merge old history, you might just have to rewrite history again if you don’t notice soon enough.
  • You can prevent people from merging (more precisely pushing) the old history by writing (5 lines) an appropriate update hook on the server. Just check whether the history of the pushed head contains a specific old commit.
于 2013-07-11T11:31:13.747 に答える
4

履歴の書き換えを回避する解決策はわかりません。

その場合、BFG-repo クリーナーのようなツールを使用して rpeo をクリーニングするのが最も簡単な解決策です (より簡単ですgit filter-branch)。

于 2013-07-04T13:40:21.703 に答える
2

正直なところ、それを行う方法は考えられません。データの整合性に関して Git がユーザーに「約束」していることを考えると、リポジトリからファイルを削除して同じハッシュを保持する方法が思い浮かびません。言い換えれば、あなたが求めていることが可能であれば、Git の信頼性ははるかに低くなります...

于 2013-07-04T14:27:19.663 に答える