32

私たちの現在のレポには数万のコミットがあり、新しいクローンはほぼギガのデータを転送します (履歴から削除された多数の jar ファイルがあります)。リポジトリで現在アクティブなファイルのみの完全な履歴を保持する新しいリポジトリを作成するか、現在のリポジトリを変更して削除されたファイルの履歴をクリアすることで、このサイズを削減したいと考えています。しかし、実際の邸宅でこれを行う方法がわかりません。

Remove deleted files from git historyのスクリプトを試しました:

for del in `cat deleted.txt`
do
    git filter-branch --index-filter "git rm --cached --ignore-unmatch $del" --prune-empty -- --all
    # The following seems to be necessary every time
    # because otherwise git won't overwrite refs/original
    git reset --hard
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --aggressive --prune=now
done;

しかし、履歴に何万もの削除されたファイルがあり、何万ものコミットがあることを考えると、スクリプトの実行には永遠の時間がかかります。2時間前に削除されたファイル1つだけに対してこれを実行し始めましたが、filter-branchコマンドはまだ実行されています.40,000以上のコミットを一度に1つずつ処理しています.これはSSDドライブを搭載した新しいMacbook pro上にあります.

ページhttps://help.github.com/articles/remove-sensitive-dataも読みましたが、これは単一のファイルを削除する場合にのみ機能します。

誰もこれを行うことができましたか?現在追跡されているファイルの履歴を保存したいのですが、履歴を保存できない場合、スペース節約のメリットが新しいリポジトリを作成する価値があるかどうかはわかりません。

4

5 に答える 5

45

すべてを削除して、必要なものを復元します

このファイルのリストを一度に 1 つずつ削除するのではなく、ほぼ逆のことを行います。つまり、すべてを削除して、保持したいファイルだけを復元します。

そのようです:

# for unix

$ git checkout master
$ git ls-files > keep-these.txt
$ git filter-branch --force --index-filter \
  "git rm  --ignore-unmatch --cached -qr . ; \
  cat $PWD/keep-these.txt | tr '\n' '\0' | xargs -d '\0' git reset -q \$GIT_COMMIT --" \
  --prune-empty --tag-name-filter cat -- --all
# for macOS

$ git checkout master
$ git ls-files > keep-these.txt
$ git filter-branch --force --index-filter \
  "git rm  --ignore-unmatch --cached -qr . ; \
  cat $PWD/keep-these.txt | tr '\n' '\0' | xargs -0 git reset -q \$GIT_COMMIT --" \
  --prune-empty --tag-name-filter cat -- --all

実行した方が早いかもしれません。

クリーンアップ手順

プロセス全体が終了したら、クリーンアップします。

$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now

# optional extra gc. Slow and may not further-reduce the repo size
$ git gc --aggressive --prune=now

前後のリポジトリサイズを比較すると、かなりの削減が示されるはずです。もちろん、保持されたファイルに触れるコミットとマージコミットのみが含まれます-たとえ空であっても(--prune-empty が機能するため)、履歴に残ります。

$GIT_COMMIT?

の使用は、git filter-branch のドキュメント(強調を追加)から、$GIT_COMMITいくつかの混乱を引き起こしたようです:

引数は、常に eval コマンドを使用してシェル コンテキストで評価されます (技術的な理由から、コミット フィルターは例外です)。その前に、 $GIT_COMMIT 環境変数は、書き換えられるコミットの ID を含むように設定されます

つまりgit filter-branch、実行時に変数が提供されます。事前に提供されるわけではありません。これは、次の no-op フィルター ブランチ コマンドを使用して疑問がある場合に実証できます。

$ git filter-branch --index-filter "echo current commit is \$GIT_COMMIT"
Rewrite d832800a85be9ef4ee6fda2fe4b3b6715c8bb860 (1/xxxxx)current commit is d832800a85be9ef4ee6fda2fe4b3b6715c8bb860
Rewrite cd86555549ac17aeaa28abecaf450b49ce5ae663 (2/xxxxx)current commit is cd86555549ac17aeaa28abecaf450b49ce5ae663
...
于 2013-07-28T14:59:27.723 に答える
5

git filter branch を 1 回だけ実行する

問題のスクリプトは、何千ものコミットを何千回も処理する予定です。通常は最後に行うだけのさまざまな (非常に遅い) ことを反復ごとに 1 回実行します。それは本当に永遠にかかります。

代わりに、スクリプトを 1 回実行して、すべてのファイルを一度に削除します。

del=`cat deleted.txt`
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch $del" \
  --prune-empty --tag-name-filter cat -- --all

プロセスが終了したらクリーンアップします。

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now

# optional extra gc. Slow and may not further-reduce the repo size
git gc --aggressive --prune=now 

ファイル数が原因で上記が失敗した場合

上記のコマンドを実行するには大きすぎるような十分なファイルが deleted.txt にある場合は、次のように書き換えることができます。

git filter-branch --force --index-filter \
  'cat /abs/path/to/deleted.txt | xargs git rm --cached --ignore-unmatch' \
  --prune-empty --tag-name-filter cat -- --all

(掃除の手順は同じです)

これは上記のバージョンと同じですが、ファイルを削除するコマンドは一度にすべてではなく、一度に 1 つずつ削除します。

于 2013-07-27T21:59:12.447 に答える
0

AD7sixによって受け入れられた回答に追加します(回答にコメントするのに十分な評判がないため):

マスター以上のものを維持したい場合は、次のことができます

  1. 不要になったタグとブランチを削除する
  2. 次に、保持したいすべてのブランチとタグで参照されるファイルのリストを作成します。
for tag in `git for-each-ref refs/tags --format='%(refname)' | cut -d / -f 3`
do
    echo $tag; sleep 3 # sleep to avoid: fatal: Unable to create '.git/index.lock': File exists.
    git checkout "$tag"
    git ls-files > ../keep_files_tag_$tag.txt
    git ls-files >> ../keep_files_all.txt
done
for branch in `git for-each-ref refs/heads --format='%(refname)' | cut -d / -f 3`
do
    echo $branch; sleep 3 # sleep to avoid: fatal: Unable to create '.git/index.lock': File exists.
    git checkout "$branch"
    git ls-files > ../keep_files_branch_$branch.txt
    git ls-files >> ../keep_files_all.txt
done
sort ../keep_files_all.txt | uniq > keep_files_uniqe.txt
于 2020-04-02T16:04:18.317 に答える