Bu yüzden ... 8GB üzerindeki bir depoda, 108.000'den fazla revizyon ile belirli bir sınırın üzerindeki tüm dosyaları bulmam gerekiyordu. Bu eksiksiz çözüme ulaşmak için yazdığım bir Ruby senaryosuyla birlikte Aristoteles'in perl senaryosunu uyarladım.
Öncelikle, git gc
- tüm nesnelerin paket dosyalarında olduğundan emin olmak için bunu yapın - paket dosyalarında olmayan nesneleri taramayız.
Sonraki CUTOFF_SIZE bayt üzerindeki tüm blobları bulmak için bu komut dosyasını çalıştırın. Çıktıyı "büyük blobs.log" gibi bir dosyaya yakalayın
require 'log4r'
GIT_PACKS_RELATIVE_PATH=File.join('.git', 'objects', 'pack', '*.pack')
CUTOFF_SIZE=1024*1024*10
begin
include Log4r
log = Logger.new 'git-find-large-objects'
log.level = INFO
log.outputters = Outputter.stdout
git_dir = %x[ git rev-parse --show-toplevel ].chomp
if git_dir.empty?
log.fatal "ERROR: must be run in a git repository"
exit 1
end
log.debug "Git Dir: '#{git_dir}'"
pack_files = Dir[File.join(git_dir, GIT_PACKS_RELATIVE_PATH)]
log.debug "Git Packs: #{pack_files.to_s}"
types = {
:blob => 1,
:tree => 1,
:commit => 1,
}
total_count = 0
counted_objects = 0
large_objects = []
IO.popen("git verify-pack -v -- #{pack_files.join(" ")}") do |pipe|
pipe.each do |line|
data = line.chomp.split(' ')
next unless types[data[1].to_sym] == 1
log.info "INPUT_THREAD: Processing object #{data[0]} type #{data[1]} size #{data[2]}"
hash = {
:sha1 => data[0],
:type => data[1],
:size => data[2].to_i,
}
total_count += hash[:size]
counted_objects += 1
if hash[:size] > CUTOFF_SIZE
large_objects.push hash
end
end
end
log.info "Input complete"
log.info "Counted #{counted_objects} totalling #{total_count} bytes."
log.info "Sorting"
large_objects.sort! { |a,b| b[:size] <=> a[:size] }
log.info "Sorting complete"
large_objects.each do |obj|
log.info "#{obj[:sha1]} #{obj[:type]} #{obj[:size]}"
end
exit 0
end
Ardından, beklemediğiniz tüm lekeleri ve üstteki INPUT_THREAD bitlerini kaldırmak için dosyayı düzenleyin. Sadece bulmak istediğiniz sha1'ler için satırınız olduğunda, aşağıdaki komut dosyasını şu şekilde çalıştırın:
cat edited-large-files.log | cut -d' ' -f4 | xargs git-find-blob | tee large-file-paths.log
git-find-blob
Komut dosyası aşağıda nerede .
use 5.008;
use strict;
use Memoize;
use Data::Dumper;
my $BLOBS = {};
MAIN: {
memoize 'check_tree';
die "usage: git-find-blob <blob1> <blob2> ... -- [<git-log arguments ...>]\n"
if not @ARGV;
while ( @ARGV && $ARGV[0] ne '--' ) {
my $arg = $ARGV[0];
open my $rev_parse, '-|', git => 'rev-parse' => '--verify', $arg or die "Couldn't open pipe to git-rev-parse: $!\n";
my $obj_name = <$rev_parse>;
close $rev_parse or die "Couldn't expand passed blob.\n";
chomp $obj_name;
print "($arg expands to $obj_name)\n";
$BLOBS->{$obj_name} = $arg;
shift @ARGV;
}
shift @ARGV;
foreach my $blob ( keys %{$BLOBS} ) {
open my $log, '-|', git => log => @ARGV, '--pretty=format:%T %h %s'
or die "Couldn't open pipe to git-log: $!\n";
while ( <$log> ) {
chomp;
my ( $tree, $commit, $subject ) = split " ", $_, 3;
my $results = check_tree( $tree );
if (%{$results}) {
print "$commit $subject\n";
foreach my $blob ( keys %{$results} ) {
print "\t" . (join ", ", @{$results->{$blob}}) . "\n";
}
}
}
}
}
sub check_tree {
my ( $tree ) = @_;
my @subtree;
my $results = {};
{
open my $ls_tree, '-|', git => 'ls-tree' => $tree
or die "Couldn't open pipe to git-ls-tree: $!\n";
while ( <$ls_tree> ) {
/\A[0-7]{6} (\S+) (\S+)\s+(.*)/
or die "unexpected git-ls-tree output";
foreach my $blob ( keys %{$BLOBS} ) {
if ( $2 eq $blob ) {
print "Found $blob in $tree:$3\n";
push @{$results->{$blob}}, $3;
}
}
push @subtree, [$2, $3] if $1 eq 'tree';
}
}
foreach my $st ( @subtree ) {
my $st_result = check_tree( $st->[0] );
foreach my $blob ( keys %{$st_result} ) {
foreach my $filename ( @{$st_result->{$blob}} ) {
my $path = $st->[1] . '/' . $filename;
push @{$results->{$blob}}, $path;
}
}
}
return $results;
}
Çıktı şöyle görünecek:
<hash prefix> <oneline log message>
path/to/file.txt
path/to/file2.txt
...
<hash prefix2> <oneline log msg...>
Ve bunun gibi. Ağacında büyük bir dosya içeren her işlem listelenecektir. grep
Bir sekmeyle başlayan satırların dışında kalırsanız ve uniq
bunun için, filtreleyerek dallara ayırabileceğiniz tüm yolların bir listesine sahip olursunuz veya daha karmaşık bir şey yapabilirsiniz.
Tekrar belirteyim: bu süreç 108.000 taahhütle 10GB'lık bir depoda başarılı bir şekilde yürütüldü. Çok sayıda blob üzerinde çalışırken tahmin ettiğimden çok daha uzun sürdü, ancak 10 saatten fazla, ezberleme bitinin çalışıp çalışmadığını görmem gerekecek ...
git hash-object
veya tarafından döndürülendirsha1("blob " + filesize + "\0" + data)
.