かなり大きな歴史を持つgitプロジェクトがあります。
具体的には、プロジェクトの初期段階でプロジェクトにはかなり多くのバイナリリソースファイルがありましたが、これらは事実上外部リソースであるため削除されました。
ただし、これらのファイルが以前にコミットされているため、リポジトリのサイズは200MBを超えています(現在、合計チェックアウトは約20MBです)。
私たちがやりたいのは、履歴を「崩壊」させ、リポジトリがそれよりも新しいリビジョンから作成されたように見えるようにすることです。例えば
1-----2-----3-----4-----+---+---+
\ /
+-----+---+---+
事実上、ある時点の前にプロジェクトの履歴を失いたいのです。この時点ではブランチは1つしかないため、複数の開始点などに対処しようとすることで問題はありません。ただし、すべての履歴を失い、現在のバージョンで新しいリポジトリを開始する必要はありません。
これは可能ですか、それとも永遠に肥大化したリポジトリを持つ運命にありますか?
バイナリの膨張を削除して、残りの履歴を保持できます。 Gitでは、以前のコミットを並べ替えて「スカッシュ」することができるため、大きなバイナリファイルを追加および削除するコミットだけを組み合わせることができます。追加がすべて1つのコミットで行われ、削除が別のコミットで行われた場合、これは各ファイルを処理するよりもはるかに簡単になります。
$ git log --stat # list all commits and commit messages
バイナリファイルを追加および削除するコミットを検索し、2bcdef
および3cdef3
などのSHA1を書き留めます。
次に、リポジトリの履歴を編集するには、バイナリを追加したコミットの親から始めて、rebase -i
コマンドとそのインタラクティブオプションを使用します。 $ 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
.
.
2行目としてsquash 3cdef3
を挿入し、リストからpick 3cdef3
と書かれている行を削除します。これで、インタラクティブrebase
のアクションのリストができました。これは、バイナリを追加および削除するコミットを1つのコミットに結合します。次に、完了するように指示すると、後続のすべてのコミットが順番に再適用されます。
$ 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
これで肥大化は解消されましたが、残りの履歴は保持されます。
git filter-branch
をグラフトで使用して、コミット番号4をブランチの新しいルートコミットにすることができます。コミット番号4のSHA1を含む1行だけのファイル.git/info/grafts
を作成します。
git log
またはgitk
を実行すると、これらのコマンドがブランチのルートとしてコミット番号4を表示することがわかります。しかし、実際にはリポジトリ内で何も変更されていません。 .git/info/grafts
を削除すると、git log
またはgitk
の出力は以前と同じになります。実際にコミット番号4を新しいルートにするには、git filter-branch
を引数なしで実行する必要があります。
JesperEの投稿のおかげで、私はgit-filter-branch
-それは実際にあなたが望むものかもしれません。 Big Filesが削除されてから変更される場合を除き、以前のコミットも保持できるようです。 git-filter-branch manページ から:
すべてのコミットからファイル(機密情報または著作権侵害を含む)を削除するとします。
git filter-branch --tree-filter 'rm filename' HEAD
必ずそのマニュアルページを読んでください...明らかに、期待どおりに動作することを確認するために、リポジトリの予備のクローンでこれを行いたいでしょう。
git-fast-export
お探しのものは?
NAME
git-fast-export - Git data exporter
SYNOPSIS
git-fast-export [options] | git-fast-import
DESCRIPTION
This program dumps the given revisions in a form suitable to be piped into git-fast-
import(1).
You can use it as a human readable bundle replacement (see git-bundle(1)), or as a kind
of an interactive git-filter-branch(1).