সুতরাং ... আমাকে 108,000 এরও বেশি সংশোধন সহ 8GB আকারের আকারের একটি রেপোতে প্রদত্ত সীমাতে সমস্ত ফাইলগুলি সন্ধান করতে হবে। এই সম্পূর্ণ সমাধানটিতে পৌঁছানোর জন্য আমি লিখেছিলাম একটি রুবি স্ক্রিপ্টের সাথে এরিস্টটলের পার্ল স্ক্রিপ্টটি মানিয়েছি।
প্রথম, git gc
- সমস্ত বস্তু প্যাকফাইলে রয়েছে তা নিশ্চিত করতে এটি করুন - আমরা প্যাক ফাইলগুলিতে নয় এমন বস্তুগুলি স্ক্যান করি না।
পরবর্তী CUTOFF_SIZE বাইটে সমস্ত ব্লব সনাক্ত করতে এই স্ক্রিপ্টটি চালান। "লার্জ-ব্লবস.লগ" এর মতো কোনও ফাইলে আউটপুট ক্যাপচার করুন
#!/usr/bin/env ruby
require 'log4r'
# The output of git verify-pack -v is:
# SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1
#
#
GIT_PACKS_RELATIVE_PATH=File.join('.git', 'objects', 'pack', '*.pack')
# 10MB cutoff
CUTOFF_SIZE=1024*1024*10
#CUTOFF_SIZE=1024
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}"
# For details on this IO, see http://stackoverflow.com/questions/1154846/continuously-read-from-stdout-of-external-process-in-ruby
#
# Short version is, git verify-pack flushes buffers only on line endings, so
# this works, if it didn't, then we could get partial lines and be sad.
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|
# The output of git verify-pack -v is:
# SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1
data = line.chomp.split(' ')
# types are blob, tree, or commit
# we ignore other lines by looking for that
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
এরপরে, আপনি অপেক্ষা না করা কোনও ব্লব এবং উপরে INPUT_THREAD বিটগুলি সরাতে ফাইলটি সম্পাদনা করুন। আপনি যে শা 1 গুলি সন্ধান করতে চান তার জন্য একবার কেবল রেখা থাকলে, নিম্নলিখিত স্ক্রিপ্টটি এভাবে চালান:
cat edited-large-files.log | cut -d' ' -f4 | xargs git-find-blob | tee large-file-paths.log
git-find-blob
স্ক্রিপ্ট নীচে যেখানে ।
#!/usr/bin/perl
# taken from: http://stackoverflow.com/questions/223678/which-commit-has-this-blob
# and modified by Carl Myers <cmyers@cmyers.org> to scan multiple blobs at once
# Also, modified to keep the discovered filenames
# vi: ft=perl
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];
#print "Processing argument $arg\n";
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;
#$obj_name eq $ARGV[0] or print "($ARGV[0] expands to $obj_name)\n";
print "($arg expands to $obj_name)\n";
$BLOBS->{$obj_name} = $arg;
shift @ARGV;
}
shift @ARGV; # drop the -- if present
#print "BLOBS: " . Dumper($BLOBS) . "\n";
foreach my $blob ( keys %{$BLOBS} ) {
#print "Printing results for blob $blob:\n";
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;
#print "Checking tree $tree\n";
my $results = check_tree( $tree );
#print "RESULTS: " . Dumper($results);
if (%{$results}) {
print "$commit $subject\n";
foreach my $blob ( keys %{$results} ) {
print "\t" . (join ", ", @{$results->{$blob}}) . "\n";
}
}
}
}
}
sub check_tree {
my ( $tree ) = @_;
#print "Calculating hits for tree $tree\n";
my @subtree;
# results = { BLOB => [ FILENAME1 ] }
my $results = {};
{
open my $ls_tree, '-|', git => 'ls-tree' => $tree
or die "Couldn't open pipe to git-ls-tree: $!\n";
# example git ls-tree output:
# 100644 blob 15d408e386400ee58e8695417fbe0f858f3ed424 filaname.txt
while ( <$ls_tree> ) {
/\A[0-7]{6} (\S+) (\S+)\s+(.*)/
or die "unexpected git-ls-tree output";
#print "Scanning line '$_' tree $2 file $3\n";
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 ) {
# $st->[0] is tree, $st->[1] is dirname
my $st_result = check_tree( $st->[0] );
foreach my $blob ( keys %{$st_result} ) {
foreach my $filename ( @{$st_result->{$blob}} ) {
my $path = $st->[1] . '/' . $filename;
#print "Generating subdir path $path\n";
push @{$results->{$blob}}, $path;
}
}
}
#print "Returning results for tree $tree: " . Dumper($results) . "\n\n";
return $results;
}
আউটপুটটি দেখতে এইরকম হবে:
<hash prefix> <oneline log message>
path/to/file.txt
path/to/file2.txt
...
<hash prefix2> <oneline log msg...>
ইত্যাদি। প্রতিটি গাছের মধ্যে একটি বড় ফাইল রয়েছে এমন প্রতিশ্রুতি তালিকাভুক্ত করা হবে। আপনি যদিgrep
কোনও ট্যাব দিয়ে শুরু হওয়া লাইনগুলি বের করেন এবং uniq
তা, আপনি মুছে ফেলার জন্য ফিল্টার-ব্রাঞ্চ করতে পারে এমন সমস্ত পাথের একটি তালিকা থাকবে বা আপনি আরও জটিল কিছু করতে পারেন।
আমাকে পুনরাবৃত্তি করা যাক: এই প্রক্রিয়াটি 10,000 জিপিওতে 108,000 কমিট করে সফলতার সাথে চলেছিল। বিপুল সংখ্যক ব্লবগুলিতে চলার সময় আমার পূর্বাভাসের তুলনায় এটি অনেক বেশি সময় নিয়েছে যদিও 10 ঘন্টােরও বেশি সময় ধরে, আমাকে দেখতে হবে যে মুখস্ত বিটটি কাজ করছে কিনা ...
git hash-object
orsha1("blob " + filesize + "\0" + data)