Git: ¿muestra la diferencia de tamaño de archivo total entre dos confirmaciones?

79

¿Es posible mostrar la diferencia de tamaño de archivo total entre dos confirmaciones? Algo como:

$ git file-size-diff 7f3219 bad418 # I wish this worked :)
-1234 bytes

He intentado:

$ git diff --patch-with-stat

Y eso muestra la diferencia de tamaño de archivo para cada archivo binario en la diferencia, pero no para los archivos de texto, y no la diferencia total de tamaño de archivo.

¿Algunas ideas?

Mathias Bynens
fuente
3
Aquí está el bashscript de 3 líneas que le da el tamaño de cierta confirmación stackoverflow.com/a/23985353/2062041
Stas Dashkovsky

Respuestas:

92

git cat-file -sgenerará el tamaño en bytes de un objeto en git. git diff-treepuede decirte las diferencias entre un árbol y otro.

Poner esto junto en un script llamado git-file-size-diffubicado en algún lugar de su PATH le dará la capacidad de llamar git file-size-diff <tree-ish> <tree-ish>. Podemos probar algo como lo siguiente:

#!/bin/bash
USAGE='[--cached] [<rev-list-options>...]

Show file size changes between two commits or the index and a commit.'

. "$(git --exec-path)/git-sh-setup"
args=$(git rev-parse --sq "$@")
[ -n "$args" ] || usage
cmd="diff-tree -r"
[[ $args =~ "--cached" ]] && cmd="diff-index"
eval "git $cmd $args" | {
  total=0
  while read A B C D M P
  do
    case $M in
      M) bytes=$(( $(git cat-file -s $D) - $(git cat-file -s $C) )) ;;
      A) bytes=$(git cat-file -s $D) ;;
      D) bytes=-$(git cat-file -s $C) ;;
      *)
        echo >&2 warning: unhandled mode $M in \"$A $B $C $D $M $P\"
        continue
        ;;
    esac
    total=$(( $total + $bytes ))
    printf '%d\t%s\n' $bytes "$P"
  done
  echo total $total
}

En uso, esto se parece a lo siguiente:

$ git file-size-diff HEAD~850..HEAD~845
-234   Documentation/RelNotes/1.7.7.txt
112    Documentation/git.txt
-4     GIT-VERSION-GEN
43     builtin/grep.c
42     diff-lib.c
594    git-rebase--interactive.sh
381    t/t3404-rebase-interactive.sh
114    t/test-lib.sh
743    tree-walk.c
28     tree-walk.h
67     unpack-trees.c
28     unpack-trees.h
total 1914

Al usarlo git-rev-parse, debería aceptar todas las formas habituales de especificar rangos de confirmación.

EDITAR: actualizado para registrar el total acumulado. Tenga en cuenta que bash ejecuta la lectura while en una subcapa, de ahí las llaves adicionales para evitar perder el total cuando la subcapa sale.

EDITAR: soporte agregado para comparar el índice con otro árbol usando un --cachedargumento para llamar en git diff-indexlugar de git diff-tree. p.ej:

$ git file-size-diff --cached master
-570    Makefile
-134    git-gui.sh
-1  lib/browser.tcl
931 lib/commit.tcl
18  lib/index.tcl
total 244
patthoyts
fuente
+1 ¡Gracias! Esto sería absolutamente perfecto si imprimiera la diferencia de tamaño total en la parte inferior. Quiero ver cuántos bytes se agregaron / eliminaron en todo el proyecto entre dos referencias (no solo por archivo, sino también en total).
Mathias Bynens
Otra pregunta: ¿por qué está comprando git-sh-setupaquí? Parece que no estás usando ninguna de las funciones que define . ¡Sólo me preguntaba!
Mathias Bynens
3
Realiza comprobaciones básicas como producir un mensaje sensible si ejecuta este comando en un directorio que no es un repositorio de git. También puede ayudar a abstraer algunas diferencias de plataforma. Aunque sobre todo un hábito. Al escribir un script de git, primero ingrese el archivo git-sh-setup.
patthoyts
1
¡Gracias por el guión! Lo archivé en resumen ( gist.github.com/cschell/9386715 ), espero que no te importe . Los impacientes ahora pueden hacer algo comocurl -s https://gist.githubusercontent.com/cschell/9386715/raw/43996adb0f785a5afc17358be7a43ff7ee973215/git-file-size-diff | bash -s <tree-ish> <tree-ish>
csch
1
@ mr5 HEAD ~ 850 son 850 confirmaciones antes de HEAD. Es solo otra notación para una confirmación y sí, puede usar una identificación de confirmación específica o una etiqueta o cualquier cosa que se pueda resolver en una confirmación. El script utiliza, git rev-parseasí que consulte la sección del manual "Especificación de revisiones" en la documentación de git-rev-parse para obtener todos los detalles. ( git-scm.com/docs/git-rev-parse )
patthoyts
21

Puede canalizar la salida de

git show some-ref:some-path-to-file | wc -c
git show some-other-ref:some-path-to-file | wc -c

y compare los 2 números.

Adam Dymitruk
fuente
9
+1 Esto es excelente para verificar rápidamente la diferencia de tamaño de un archivo entre versiones. Pero, ¿cómo se puede usar esto para obtener la diferencia total de archivos entre dos confirmaciones? Quiero ver cuántos bytes se agregaron / eliminaron en todo el proyecto entre dos referencias.
Mathias Bynens
1
Puede omitir | wc -csi usa en cat-file -slugar deshow
neu242
Usando la mejora sugerida por @ neu242, escribí esta función bash: gdbytes () { echo "$(git cat-file -s $1:$3) -> $(git cat-file -s $2:$3)" } lo que facilita ver cómo cambió el tamaño del archivo desde la última confirmación con, por ejemplo,gdbytes @~ @ index.html
tknomad
si some-ref:se omite la parte, ¿obtiene el tamaño del archivo en el directorio de trabajo?
40detectives
3

Hice un script bash para comparar ramas / confirmaciones, etc.por tamaño real de archivo / contenido. Se puede encontrar en https://github.com/matthiaskrgr/gitdiffbinstat y también detecta cambios de nombre de archivos.

matthiaskrgr
fuente
2
¿Tienes un ejemplo de uso de esto?
AlecRust
3

Ampliando la respuesta de matthiaskrgr , https://github.com/matthiaskrgr/gitdiffbinstat se puede usar como los otros scripts:

gitdiffbinstat.sh HEAD..HEAD~4

Imo realmente funciona bien, mucho más rápido que cualquier otra cosa publicada aquí. Salida de muestra:

$ gitdiffbinstat.sh HEAD~6..HEAD~7
 HEAD~6..HEAD~7
 704a8b56161d8c69bfaf0c3e6be27a68f27453a6..40a8563d082143d81e622c675de1ea46db706f22
 Recursively getting stat for path "./c/data/gitrepo" from repo root......
 105 files changed in total
  3 text files changed, 16 insertions(+), 16 deletions(-) => [±0 lines]
  102 binary files changed 40374331 b (38 Mb) -> 39000258 b (37 Mb) => [-1374073 b (-1 Mb)]
   0 binary files added, 3 binary files removed, 99 binary files modified => [-3 files]
    0 b  added in new files, 777588 b (759 kb) removed => [-777588 b (-759 kb)]
    file modifications: 39596743 b (37 Mb) -> 39000258 b (37 Mb) => [-596485 b (-582 kb)]
    / ==>  [-1374073 b (-1 Mb)]

El directorio de salida es funky con ./c/data ... ya que / c es en realidad la raíz del sistema de archivos.

invitado
fuente
No era necesario que comentaras la publicación de Matthias; en su lugar, podrías haber sugerido una edición, con estos detalles que él no proporcionó. Según los estándares actuales, su respuesta se consideraría una "respuesta de solo enlace" y se eliminaría, por lo que este tipo de detalles son importantes.
Mogsdad
¿Quién puede tomar mi respuesta e incluirla en matthias?
invitado
Si lo desea, puede realizar una edición sugerida usted mismo. (En mi experiencia, los revisores tienden a rechazarlo, pero una explicación clara en el Resumen de edición podría ayudar). Pero tal vez no fui claro en mi comentario para ti ... tu respuesta es una respuesta independiente , una buena actualización de la respuesta anterior de Matthias. No era necesario que incluyeras el texto que explicaba lo que querías comentar, eso es todo. Edité la respuesta de una manera que le da el crédito apropiado a Matthias. No necesitas hacer más.
Mogsdad
2

Un comentario al script: git-file-size-diff, sugerido por patthoyts. El script es muy útil, sin embargo, he encontrado dos problemas:

  1. Cuando alguien cambia los permisos en el archivo, git devuelve otro tipo en la declaración del caso:

    T) echo >&2 "Skipping change of type"
    continue ;;
    
  2. Si un valor sha-1 ya no existe (por alguna razón), el script falla. Necesita validar el sha antes de obtener el tamaño del archivo:

    $(git cat-file -e $D) if [ "$?" = 1 ]; then continue; fi

La declaración completa del caso se verá así:

case $M in
      M) $(git cat-file -e $D)
         if [ "$?" = 1 ]; then continue; fi
         $(git cat-file -e $C)
         if [ "$?" = 1 ]; then continue; fi
         bytes=$(( $(git cat-file -s $D) - $(git cat-file -s $C) )) ;;
      A) $(git cat-file -e $D)
         if [ "$?" = 1 ]; then continue; fi
         bytes=$(git cat-file -s $D) ;;
      D) $(git cat-file -e $C)
         if [ "$?" = 1 ]; then continue; fi
         bytes=-$(git cat-file -s $C) ;;
      T) echo >&2 "Skipping change of type"
         continue ;;
      *)
        echo >&2 warning: unhandled mode $M in \"$A $B $C $D $M $P\"
        continue
        ;;
    esac
Richard Nilsson
fuente