1. ホーム
  2. git

[解決済み] git リポジトリの履歴を折りたたむ

2023-05-19 13:12:29

質問

私たちは、かなり大きな履歴を持つgitプロジェクトを持っています。

特に、プロジェクトの初期には非常に多くのバイナリリソースファイルがありましたが、これらは事実上外部リソースであるため、現在では削除されています。

しかし、これらのファイルを以前にコミットしたため、リポジトリのサイズは >200MB (現在の総チェックアウトは ~20MB) になっています。

私たちが行いたいことは、リポジトリが実際よりも遅いリビジョンから作成されたように見えるように、履歴を "collapse"することです。たとえば、次のようになります。

1-----2-----3-----4-----+---+---+
                   \       /
                    +-----+---+---+

  1. リポジトリ作成
  2. 大量のバイナリ ファイルが追加されました。
  3. 削除された大量のバイナリ ファイル
  4. リポジトリの新しい意図された「開始」。

つまり、ある時点より前のプロジェクトの履歴を失いたいのです。この時点ではブランチは 1 つだけなので、複数の開始点を扱うような複雑なことはありません。しかし、すべての履歴を失い、現在のバージョンで新しいリポジトリを開始したくはありません。

これは可能ですか、それとも私たちは永遠に肥大化したリポジトリを持つ運命にあるのでしょうか?

どのように解決するのですか?

バイナリの肥大化を取り除き、残りの履歴を維持することができます。Git では、以前のコミットを並べ替えたり「つぶしたり」することができるので、大きなバイナリ ファイルを追加したり削除したりするコミットだけを結合することができます。追加を一つのコミットで、削除を別のコミットで行った場合、それぞれのファイルを扱うよりずっと簡単でしょう。

$ git log --stat       # list all commits and commit messages 

これを検索して、あなたのバイナリファイルを追加・削除したコミットを探し、その SHA1 を記録します。 2bcdef3cdef3 .

次に、レポの履歴を編集するために rebase -i コマンドの interactive オプションで、バイナリを追加したコミットの親から始めてください。これで $EDITOR が起動し、以下のコミットのリストが表示されます。 2bcdef :

$ git rebase -i 2bcdef^    # generate a pick list of all commits starting with 2bcdef
# Rebasing zzzzzz onto yyyyyyy 
# 
# Commands: 
#  pick = use commit 
#  edit = use commit, but stop for amending 
#  squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST.
#
pick 2bcdef   Add binary files and other edits
pick xxxxxx   Another change
  .
  .
pick 3cdef3   Remove binary files; link to them as external resources
  .
  .

挿入 squash 3cdef3 を2行目として挿入し、以下の行を削除します。 pick 3cdef3 という行をリストから削除します。 これで、対話型アクションのリストができました。 rebase は、バイナリを追加したり削除したりしたコミットをひとつのコミットにまとめ、その diff にはそれらのコミットでの変更点をそのまま反映させます。そして、完了を告げると、それ以降のすべてのコミットを順番に再適用します。

$ git rebase --continue

これは1〜2分かかります。

これで、バイナリが出入りすることのないリポジトリができました。 しかし、バイナリはまだスペースを取っています。デフォルトでは、Git は変更をゴミ箱に回収する前に 30 日間保持するので、気が変わったら削除することができます。 もし、今すぐ削除したいのであれば

$ git reflog expire --expire=1.minute refs/heads/master
      #all deletions up to 1 minute  ago available to be garbage-collected
$ git fsck --unreachable      # lists all the blobs(files) that will be garbage-collected
$ git prune
$ git gc                      

これで、肥大化した部分を削除しましたが、残りの履歴は残しました。