ver tag repositorio origin modificados example eliminar archivos git

repositorio - git push tag



Encuentra archivos en git repo sobre x megabytes, que no existen en HEAD (10)

Tengo un repositorio de Git en el que almaceno cosas aleatorias. Principalmente scripts aleatorios, archivos de texto, sitios web que he diseñado, etc.

Hay algunos archivos binarios grandes que he eliminado a lo largo del tiempo (generalmente de 1 a 5 MB), que están disponibles para aumentar el tamaño del repositorio, que no necesito en el historial de revisiones.

Básicamente quiero poder hacer ...

me@host:~$ [magic command or script] aad29819a908cc1c05c3b1102862746ba29bafc0 : example/blah.psd : 3.8MB : 130 days old 6e73ca29c379b71b4ff8c6b6a5df9c7f0f1f5627 : another/big.file : 1.12MB : 214 days old

..entonces podrá ir a través de cada resultado, verificando si ya no es necesario y luego retirándolo (probablemente usando filter-branch )


Desea utilizar BFG Repo-Cleaner , una alternativa más rápida y sencilla a git-filter-branch específicamente diseñada para eliminar archivos grandes de repositorios Git.

Descargue el jar BFG (requiere Java 6 o superior) y ejecute este comando:

$ java -jar bfg.jar --strip-blobs-bigger-than 1M my-repo.git

Cualquier archivo de más de 1 M de tamaño (que no esté en su última confirmación) se eliminará del historial de su repositorio Git. A continuación, puede usar git gc para limpiar los datos muertos:

$ git gc --prune=now --aggressive

El BFG suele ser 10-50 veces más rápido que ejecutar git-filter-branch y las opciones se adaptan a estos dos casos de uso comunes:

  • Eliminando Crazy Big Files
  • Eliminar contraseñas, credenciales y otros datos privados

Descripción completa: soy el autor de BFG Repo-Cleaner.


Ouch ... ese primer guión (por Aristóteles), es bastante lento. En el repositorio git.git, buscando archivos> 100k, mastica la CPU por unos 6 minutos.

También parece tener varios SHA incorrectos impresos; a menudo se imprimirá un SHA que no tiene nada que ver con el nombre de archivo mencionado en la siguiente línea.

Aquí hay una versión más rápida. El formato de salida es diferente, pero es muy rápido y, por lo que yo sé, también es correcto.

El programa es un poco más largo, pero mucho es verborrea.

#!/usr/bin/perl use 5.10.0; use strict; use warnings; use File::Temp qw(tempdir); END { chdir( $ENV{HOME} ); } my $tempdir = tempdir( "git-files_tempdir.XXXXXXXXXX", TMPDIR => 1, CLEANUP => 1 ); my $min = shift; $min =~ /^/d+$/ or die "need a number"; # ---------------------------------------------------------------------- my @refs =qw(HEAD); @refs = @ARGV if @ARGV; # first, find blob SHAs and names (no sizes here) open( my $objects, "-|", "git", "rev-list", "--objects", @refs) or die "rev-list: $!"; open( my $blobfile, ">", "$tempdir/blobs" ) or die "blobs out: $!"; my ( $blob, $name ); my %name; my %size; while (<$objects>) { next unless / ./; # no commits or top level trees ( $blob, $name ) = split; $name{$blob} = $name; say $blobfile $blob; } close($blobfile); # next, use cat-file --batch-check on the blob SHAs to get sizes open( my $sizes, "-|", "< $tempdir/blobs git cat-file --batch-check | grep blob" ) or die "cat-file: $!"; my ( $dummy, $size ); while (<$sizes>) { ( $blob, $dummy, $size ) = split; next if $size < $min; $size{ $name{$blob} } = $size if ( $size{ $name{$blob} } || 0 ) < $size; } my @names_by_size = sort { $size{$b} <=> $size{$a} } keys %size; say " The size shown is the largest that file has ever attained. But note that it may not be that big at the commit shown, which is merely the most recent commit affecting that file. "; # finally, for each name being printed, find when it was last updated on each # branch that we''re concerned about and print stuff out for my $name (@names_by_size) { say "$size{$name}/t$name"; for my $r (@refs) { system("git --no-pager log -1 --format=''%x09%h%x09%x09%ar%x09$r'' $r -- $name"); } print "/n"; } print "/n";


El guión de Aristote te mostrará lo que quieres. También necesita saber que los archivos eliminados seguirán ocupando espacio en el repositorio.

De forma predeterminada, Git mantiene los cambios durante alrededor de 30 días antes de que puedan ser recolectados. Si quieres eliminarlos ahora:

$ 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(file contents) that will be garbage-collected $ git prune $ git gc

Un comentario al margen: aunque soy un gran admirador de Git, Git no aporta ninguna ventaja al almacenar su colección de "scripts aleatorios, archivos de texto, sitios web" y archivos binarios. Git realiza un seguimiento de los cambios en el contenido, en particular el historial de cambios coordinados entre muchos archivos de texto, y lo hace de manera muy eficiente y efectiva. Como su pregunta lo ilustra, Git no tiene buenas herramientas para rastrear cambios de archivos individuales. Y no rastrea los cambios en los binarios, por lo que cualquier revisión almacena otra copia completa en el repositorio.

Por supuesto, este uso de Git es una manera perfectamente buena de familiarizarse con la forma en que funciona.


Un poco tarde para la fiesta, pero git-fat tiene esta funcionalidad incorporada.

Simplemente instálalo con pip y ejecuta git fat -a find 100000 donde el número al final está en Bytes.


#!/bin/bash if [ "$#" != 1 ] then echo ''git large.sh [size]'' exit fi declare -A big_files big_files=() echo printing results while read commit do while read bits type sha size path do if [ "$size" -gt "$1" ] then big_files[$sha]="$sha $size $path" fi done < <(git ls-tree --abbrev -rl $commit) done < <(git rev-list HEAD) for file in "${big_files[@]}" do read sha size path <<< "$file" if git ls-tree -r HEAD | grep -q $sha then echo $file fi done

Fuente


Esta es una adaptación del script git-find-blob que publiqué anteriormente :

#!/usr/bin/perl use 5.008; use strict; use Memoize; sub usage { die "usage: git-large-blob <size[b|k|m]> [<git-log arguments ...>]/n" } @ARGV or usage(); my ( $max_size, $unit ) = ( shift =~ /^(/d+)([bkm]?)/z/ ) ? ( $1, $2 ) : usage(); my $exp = 10 * ( $unit eq ''b'' ? 0 : $unit eq ''k'' ? 1 : 2 ); my $cutoff = $max_size * 2**$exp; sub walk_tree { my ( $tree, @path ) = @_; my @subtree; my @r; { open my $ls_tree, ''-|'', git => ''ls-tree'' => -l => $tree or die "Couldn''t open pipe to git-ls-tree: $!/n"; while ( <$ls_tree> ) { my ( $type, $sha1, $size, $name ) = //A[0-7]{6} (/S+) (/S+) +(/S+)/t(.*)/; if ( $type eq ''tree'' ) { push @subtree, [ $sha1, $name ]; } elsif ( $type eq ''blob'' and $size >= $cutoff ) { push @r, [ $size, @path, $name ]; } } } push @r, walk_tree( $_->[0], @path, $_->[1] ) for @subtree; return @r; } memoize ''walk_tree''; open my $log, ''-|'', git => log => @ARGV, ''--pretty=format:%T %h %cr'' or die "Couldn''t open pipe to git-log: $!/n"; my %seen; while ( <$log> ) { chomp; my ( $tree, $commit, $age ) = split " ", $_, 3; my $is_header_printed; for ( walk_tree( $tree ) ) { my ( $size, @path ) = @$_; my $path = join ''/'', @path; next if $seen{ $path }++; print "$commit $age/n" if not $is_header_printed++; print "/t$size/t$path/n"; } }


Mi simplificación de python de https://.com/a/10099633/131881

#!/usr/bin/env python import os, sys bigfiles = [] for revision in os.popen(''git rev-list HEAD''): for f in os.popen(''git ls-tree -zrl %s'' % revision).read().split(''/0''): if f: mode, type, commit, size, path = f.split(None, 4) if int(size) > int(sys.argv[1]): bigfiles.append((int(size), commit, path)) for f in sorted(set(bigfiles)): print f


Script de Python para hacer lo mismo (basado en esta publicación ):

#!/usr/bin/env python import os, sys def getOutput(cmd): return os.popen(cmd).read() if (len(sys.argv) <> 2): print "usage: %s size_in_bytes" % sys.argv[0] else: maxSize = int(sys.argv[1]) revisions = getOutput("git rev-list HEAD").split() bigfiles = set() for revision in revisions: files = getOutput("git ls-tree -zrl %s" % revision).split(''/0'') for file in files: if file == "": continue splitdata = file.split() commit = splitdata[2] if splitdata[3] == "-": continue size = int(splitdata[3]) path = splitdata[4] if (size > maxSize): bigfiles.add("%10d %s %s" % (size, commit, path)) bigfiles = sorted(bigfiles, reverse=True) for f in bigfiles: print f


Este bash "one-liner" muestra todos los objetos blob en el repositorio que tienen más de 10 MiB y no están presentes en HEAD ordenados de menor a mayor.

Es muy rápido , fácil de copiar y pegar, y solo requiere las utilidades estándar de GNU.

git rev-list --objects --all / | git cat-file --batch-check=''%(objecttype) %(objectname) %(objectsize) %(rest)'' / | awk -v min_mb=10 ''/^blob/ && $3 >= min_mb*2^20 {print substr($0,6)}'' / | grep -vF "$(git ls-tree -r HEAD | awk ''{print $3}'')" / | sort --numeric-sort --key=2 / | cut --complement --characters=13-40 / | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

Esto generará resultados como este:

2ba44098e28f 12MiB path/to/hires-image.png bd1741ddce0d 63MiB path/to/some-video-1080p.mp4

Para obtener más información, incluido un formato de salida más adecuado para el procesamiento adicional de scripts, vea mi respuesta original en una pregunta similar.


Script de ruby ​​más compacto:

#!/usr/bin/env ruby -w head, treshold = ARGV head ||= ''HEAD'' Megabyte = 1000 ** 2 treshold = (treshold || 0.1).to_f * Megabyte big_files = {} IO.popen("git rev-list #{head}", ''r'') do |rev_list| rev_list.each_line do |commit| commit.chomp! for object in `git ls-tree -zrl #{commit}`.split("/0") bits, type, sha, size, path = object.split(//s+/, 5) size = size.to_i big_files[sha] = [path, size, commit] if size >= treshold end end end big_files.each do |sha, (path, size, commit)| where = `git show -s #{commit} --format=''%h: %cr''`.chomp puts "%4.1fM/t%s/t(%s)" % [size.to_f / Megabyte, path, where] end

Uso:

ruby big_file.rb [rev] [size in MB] $ ruby big_file.rb master 0.3 3.8M example/blah.psd (aad2981: 4 months ago) 1.1M another/big.file (6e73ca2: 2 weeks ago)