515

300 MB の git リポジトリがあります。現在チェックアウトしているファイルの合計サイズは 2 MB で、残りの git リポジトリの合計サイズは 298 MB です。これは基本的に、数 MB を超えてはならないコードのみのレポです。

誰かが誤っていくつかの大きなファイル (ビデオ、画像など) をコミットし、それらを削除したと思われますが、git からではなく、履歴にはまだ役に立たない大きなファイルが含まれています。git履歴で大きなファイルを見つけるにはどうすればよいですか? 400 以上のコミットがあるため、1 つずつ進めるのは現実的ではありません。

:私の質問は、ファイルを削除する方法ではなく、そもそもファイルを見つける方法です。

4

13 に答える 13

172

私は過去に、このスクリプトが git リポジトリ内の大きな (そして目立たない) オブジェクトを見つけるのに非常に役立つことを発見しました:


#!/bin/bash
#set -x 
 
# Shows you the largest objects in your repo's pack file.
# Written for osx.
#
# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
# @author Antony Stubbs
 
# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
IFS=$'\n';
 
# list all objects including their size, sort by size, take top 10
objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head`
 
echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."
 
output="size,pack,SHA,location"
allObjects=`git rev-list --all --objects`
for y in $objects
do
    # extract the size in bytes
    size=$((`echo $y | cut -f 5 -d ' '`/1024))
    # extract the compressed size in bytes
    compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024))
    # extract the SHA
    sha=`echo $y | cut -f 1 -d ' '`
    # find the objects location in the repository tree
    other=`echo "${allObjects}" | grep $sha`
    #lineBreak=`echo -e "\n"`
    output="${output}\n${size},${compressedSize},${other}"
done
 
echo -e $output | column -t -s ', '

これにより、ブロブのオブジェクト名 (SHA1sum) が得られ、次のようなスクリプトを使用できます。

...これらの各ブロブを指すコミットを見つける。

于 2012-05-16T16:01:20.903 に答える
17

BFG Repo-Cleanerを使用する必要があります。

ウェブサイトによると:

BFG は、Git リポジトリの履歴から不正なデータを削除するための git-filter-branch に代わる、よりシンプルで高速な代替手段です。

  • 非常に大きなファイルを削除する
  • パスワード、資格情報、その他の個人データの削除

リポジトリのサイズを縮小するための古典的な手順は次のとおりです。

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push
于 2014-03-11T18:45:18.073 に答える
14

大きなファイルのリストのみが必要な場合は、次のワンライナーを提供したいと思います。

join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n

その出力は次のようになります。

commit       file name                                  size in bytes

72e1e6d20... db/players.sql 818314
ea20b964a... app/assets/images/background_final2.png 6739212
f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545
1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216
bc83d216d... app/assets/images/background_1forfinal.psd 95533848

リストの最後のエントリは、git 履歴の中で最大のファイルを指しています。

この出力を使用して、履歴に必要なBFGを削除していないことを確認できます。

これを機能させるには、リポジトリをクローンする必要があることに注意してください--mirror

于 2015-10-07T13:05:19.680 に答える
7

Windows を使用している場合は、リポジトリ内の最大 10 個のファイルを出力する PowerShell スクリプトを次に示します。

$revision_objects = git rev-list --objects --all;
$files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) };
$files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10
于 2016-05-14T23:19:04.460 に答える
4

試してみてくださいgit ls-files | xargs du -hs --threshold=1M

CI パイプラインで以下のコマンドを使用します。git リポジトリで大きなファイルが見つかった場合は停止します。

test $(git ls-files | xargs du -hs --threshold=1M 2>/dev/null | tee /dev/stderr | wc -l) -gt 0 && { echo; echo "Aborting due to big files in the git repository."; exit 1; } || true
于 2018-11-15T05:23:10.083 に答える
3

--batch-checkGit 1.8.3 へのコマンドライン スイッチ (使用する必要があります) は引数を受け入れないため、最も一般的な回答を利用できませんでした。次の手順は、CentOS 6.5 と Bash 4.1.2 で試行されました。

重要な概念

Git では、blobという用語はファイルの内容を意味します。コミットによって、ファイルまたはパス名の内容が変更される可能性があることに注意してください。したがって、同じファイルがコミットに応じて異なる BLOB を参照する可能性があります。特定のファイルは、あるコミットではディレクトリ階層で最大になり、別のコミットでは最大ではない可能性があります。したがって、大きなファイルではなく大きなコミットを見つけるという問題は、問題を正しい視点に置きます。

せっかちな人向け

サイズの降順でブロブのリストを出力するコマンドは次のとおりです。

git cat-file --batch-check < <(git rev-list --all --objects  | \
awk '{print $1}')  | grep blob  | sort -n -r -k 3

出力例:

3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620

このようなブロブを削除するには、他の回答で述べたように、 BFG Repo Cleanerを使用します。BLOB ハッシュのみを含むファイルblobs.txtがあるとします。たとえば、次のようになります。

3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2

行う:

java -jar bfg.jar -bi blobs.txt <repo_dir>

問題は、コミットを見つけることです。これは、ブロブを見つけるよりも多くの作業です。知るために、読んでください。

今後の作業

コミット ハッシュが与えられた場合、それに関連付けられたすべてのオブジェクト (ブロブを含む) のハッシュを出力するコマンドは次のとおりです。

git ls-tree -r --full-tree <commit_hash>

そのため、リポジトリ内のすべてのコミットでそのような出力を利用できる場合、ブロブ ハッシュが与えられると、一連のコミットは出力のいずれかに一致するものになります。このアイデアは、次のスクリプトにエンコードされています。

#!/bin/bash
DB_DIR='trees-db'

find_commit() {
    cd ${DB_DIR}
    for f in *; do
        if grep -q $1 ${f}; then
            echo ${f}
        fi
    done
    cd - > /dev/null
}

create_db() {
    local tfile='/tmp/commits.txt'
    mkdir -p ${DB_DIR} && cd ${DB_DIR}
    git rev-list --all > ${tfile}

    while read commit_hash; do
        if [[ ! -e ${commit_hash} ]]; then
            git ls-tree -r --full-tree ${commit_hash} > ${commit_hash}
        fi
    done < ${tfile}
    cd - > /dev/null
    rm -f ${tfile}
}

create_db

while read id; do
    find_commit ${id};
done

という名前のファイルに内容が保存されている場合find-commits.sh、通常の呼び出しは次のようになります。

cat blobs.txt | find-commits.sh

前述のように、ファイルblobs.txtには BLOB ハッシュが 1 行に 1 つずつ一覧表示されます。このcreate_db()関数は、現在のディレクトリのサブディレクトリにすべてのコミット リストのキャッシュを保存します。

2 つの Intel(R) Xeon(R) CPU E5-2620 2.00GHz プロセッサを搭載したシステムで、OS によって 24 個の仮想コアとして提示された私の実験からのいくつかの統計:

  • リポジトリ内のコミットの総数 = ほぼ 11,000
  • ファイル作成速度 = 126 ファイル/秒。このスクリプトは、コミットごとに 1 つのファイルを作成します。これは、キャッシュが初めて作成されるときにのみ発生します。
  • キャッシュ作成のオーバーヘッド = 87 秒。
  • 平均検索速度 = 522 コミット/秒。キャッシュの最適化により、実行時間が 80% 短縮されました。

スクリプトはシングル スレッドであることに注意してください。したがって、一度に使用されるコアは 1 つだけです。

于 2019-12-10T15:51:02.550 に答える