2008-10-22 11 views
16

Esto es una especie de seguimiento de this question.Git: buscar blobs duplicados (archivos) en este árbol

Si hay varios blobs con los mismos contenidos, solo se almacenan una vez en el repositorio de git porque sus SHA-1 serán idénticos. ¿Cómo se podría encontrar todos los archivos duplicados para un árbol determinado?

¿Tendría que caminar por el árbol y buscar hashes duplicados, o proporciona git backlinks desde cada blob a todos los archivos de un árbol que hace referencia a él?

Respuesta

9

Ejecutar esto en la base de código en la que trabajo fue una revelación que puedo decirle!

#!/usr/bin/perl 

# usage: git ls-tree -r HEAD | $PROGRAM_NAME 

use strict; 
use warnings; 

my $sha1_path = {}; 

while (my $line = <STDIN>) { 
    chomp $line; 

    if ($line =~ m{ \A \d+ \s+ \w+ \s+ (\w+) \s+ (\S+) \z }xms) { 
     my $sha1 = $1; 
     my $path = $2; 

     push @{$sha1_path->{$sha1}}, $path; 
    } 
} 

foreach my $sha1 (keys %$sha1_path) { 
    if (scalar @{$sha1_path->{$sha1}} > 1) { 
     foreach my $path (@{$sha1_path->{$sha1}}) { 
      print "$sha1 $path\n"; 
     } 

     print '-' x 40, "\n"; 
    } 
} 
+0

Tienes razón ... ¡Los resultados son muy interesantes! – Readonly

+0

Poca corrección para admitir espacios en sus rutas: cambie el final de la expresión regular de "\ s + (\ S +) \ z" a "\ s + (. +) \ Z". –

4

Las respuestas de scripting de su pregunta vinculada se aplican aquí también.

Pruebe el siguiente comando git desde la raíz de su repositorio de git.

git ls-tree -r HEAD 

Esto genera una lista recursiva de todas las 'notas' en la cabeza actual, incluyendo su camino y su identificador de SHA1.

git no mantiene enlaces hacia atrás de un blob a árbol, entonces sería una tarea de scripting (perl, python?) Analizar un resultado git ls-tree -r y crear un informe resumido de todos los sha1 que aparecen más de una vez en la lista .

7

acaba de hacer una sola línea que pone de relieve los duplicados prestados por git ls-tree.
podría ser útil

git ls-tree -r HEAD | 
    sort -t ' ' -k 3 | 
    perl -ne '$1 &&/$1\t/ && print "\e[0;31m" ;/([0-9a-f]{40})\t/; print "$_\e[0m"' 
+0

¡Gracias por esto! Muy útil. –

21
[alias] 
    # find duplicate files from root 
    alldupes = !"git ls-tree -r HEAD | cut -c 13- | sort | uniq -D -w 40" 

    # find duplicate files from the current folder (can also be root) 
    dupes = !"cd `pwd`/$GIT_PREFIX && git ls-tree -r HEAD | cut -c 13- | sort | uniq -D -w 40" 
+1

Corto y dulce, gracias. – sinelaw

0

más general:

(for f in `find .`; do test -f $f && echo $(wc -c <$f) $(md5 -q $f) ; done) |sort |uniq -c |grep -vE '^\s*1\b' |sed 's/.* //' > ~/dup.md5 ; \ 
(for f in `find .`; do test -f $f && echo $(wc -c <$f) $(md5 -q $f) $f; done) |fgrep -f ~/dup.md5 |sort 
+0

Esto no parece responder a la pregunta, ya que no busca en absoluto el historial de Git. También tenga en cuenta 'find -type f' y 'du'; su versión actual es muy ineficiente (revisa los archivos varias veces). No downvoted porque esto podría ser útil, supongo. – remram

0

Para los usuarios de Windows/PowerShell:

git ls-tree -r HEAD | group { $_ -replace '.{12}(.{40}).*', '$1' } | ? { $_.Count -gt 1 } | select -expand Group 

Esto da salida a algo como:

100644 blob 8a49bcbae578c405ba2596c06f46fabbbc331c64 filename1 
100644 blob 8a49bcbae578c405ba2596c06f46fabbbc331c64 filename2 
100644 blob c1720b20bb3ad5761c1afb6a3113fbc2ba94994e filename3 
100644 blob c1720b20bb3ad5761c1afb6a3113fbc2ba94994e filename4 
Cuestiones relacionadas