Git: Gesamtgröße der Dateigröße zwischen zwei Commits anzeigen?

78

Ist es möglich, den Gesamtunterschied der Dateigröße zwischen zwei Commits anzuzeigen? Etwas wie:

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

Ich habe es versucht:

$ git diff --patch-with-stat

Und das zeigt den Unterschied in der Dateigröße für jede Binärdatei im Diff - aber nicht für Textdateien und nicht den Gesamtunterschied in der Dateigröße.

Irgendwelche Ideen?

Mathias Bynens
quelle
3
Hier ist das 3-zeilige Bashscript, das Ihnen die Größe eines bestimmten Commits angibt. Stackoverflow.com/a/23985353/2062041
Stas Dashkovsky

Antworten:

90

git cat-file -sgibt die Größe eines Objekts in Git in Byte aus. git diff-treekann Ihnen die Unterschiede zwischen einem Baum und einem anderen sagen.

Wenn Sie dies in einem Skript zusammenfassen, das git-file-size-diffsich irgendwo auf Ihrem Pfad befindet, können Sie es aufrufen git file-size-diff <tree-ish> <tree-ish>. Wir können so etwas wie das Folgende versuchen:

#!/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
}

Im Gebrauch sieht dies wie folgt aus:

$ 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

Durch die Verwendung git-rev-parsesollten alle üblichen Methoden zum Festlegen von Festschreibungsbereichen akzeptiert werden.

BEARBEITEN: aktualisiert, um die kumulierte Summe aufzuzeichnen. Beachten Sie, dass bash das while-Lesen in einer Unterschale ausführt, daher die zusätzlichen geschweiften Klammern, um zu vermeiden, dass beim Verlassen der Unterschale die Summe verloren geht.

BEARBEITEN: Unterstützung für den Vergleich des Index mit einem anderen Baum hinzugefügt, indem stattdessen ein --cachedArgument zum Aufrufen git diff-indexverwendet wird git diff-tree. z.B:

$ 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
quelle
+1 Danke! Dies wäre absolut perfekt, wenn der Gesamtgrößenunterschied unten ausgedruckt würde. Ich möchte sehen, wie viele Bytes projektweit zwischen zwei Refs hinzugefügt / entfernt wurden (nicht nur pro Datei, sondern auch insgesamt).
Mathias Bynens
Eine andere Frage: Warum beziehen Sie git-sh-setuphier? Sie scheinen keine der darin definierten Funktionen zu verwenden . Ich wundere mich nur!
Mathias Bynens
3
Es führt grundlegende Überprüfungen durch, z. B. das Erstellen einer sinnvollen Nachricht, wenn Sie diesen Befehl in einem Verzeichnis ausführen, das kein Git-Repository ist. Es kann auch helfen, einige Plattformunterschiede auszugleichen. Meistens jedoch Gewohnheit. Wenn Sie ein Git-Skript schreiben, bringen Sie zuerst die Git-Sh-Setup-Datei ein.
Patthoyts
1
Danke für das Skript! Ich habe es in einem Kern archiviert ( gist.github.com/cschell/9386715 ), ich hoffe es macht Ihnen nichts aus. Ungeduldige können jetzt so etwas tuncurl -s https://gist.githubusercontent.com/cschell/9386715/raw/43996adb0f785a5afc17358be7a43ff7ee973215/git-file-size-diff | bash -s <tree-ish> <tree-ish>
csch
1
@ mr5 HEAD ~ 850 ist 850 Commits vor HEAD. Es ist nur eine andere Notation für ein Commit, und ja, Sie können eine bestimmte Commit-ID oder ein Tag oder alles verwenden, was in ein Commit aufgelöst werden kann. Das Skript verwendet git rev-parsedaher die vollständigen Details im Handbuchabschnitt "Festlegen von Revisionen" in der git-rev-parse-Dokumentation. ( git-scm.com/docs/git-rev-parse )
Patthoyts
20

Sie können die Ausgabe auspfeifen

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

und vergleiche die 2 Zahlen.

Adam Dymitruk
quelle
8
+1 Dies ist ideal, um schnell den Größenunterschied einer Datei zwischen Versionen zu überprüfen. Aber wie kann dies verwendet werden, um die gesamte Dateidifferenz zwischen zwei Commits zu ermitteln? Ich möchte sehen, wie viele Bytes projektweit zwischen zwei Refs hinzugefügt / entfernt wurden.
Mathias Bynens
1
Sie können das überspringen, | wc -cwenn Sie cat-file -sanstelle vonshow
neu242
Unter Verwendung der von @ neu242 vorgeschlagenen Verbesserung habe ich diese Bash-Funktion geschrieben: Damit gdbytes () { echo "$(git cat-file -s $1:$3) -> $(git cat-file -s $2:$3)" } ist es leicht zu sehen, wie sich die Dateigröße seit dem letzten gdbytes @~ @ index.html
Festschreiben
Wenn das some-ref:Teil übersprungen wird, erhalten Sie die Dateigröße im Arbeitsverzeichnis?
40 Detectives
3

Aufbauend auf matthiaskrgr Antwort , https://github.com/matthiaskrgr/gitdiffbinstat kann wie die anderen Skripten verwendet werden:

gitdiffbinstat.sh HEAD..HEAD~4

Imo es funktioniert wirklich gut, viel schneller als alles andere hier gepostet. Beispielausgabe:

$ 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)]

Das Ausgabeverzeichnis ist funky mit ./c/data ... da / c eigentlich das Dateisystemstamm ist.

Gast
quelle
Sie mussten Matthias 'Beitrag nicht kommentieren - Sie hätten stattdessen eine Bearbeitung vorschlagen können, mit diesen Details, die er nicht zur Verfügung stellte. Nach den derzeitigen Standards würde seine Antwort als "Nur-Link-Antwort" betrachtet und gelöscht, daher sind diese Art von Details wichtig.
Mogsdad
Wer kann meine Antwort nehmen und in Matthias aufnehmen?
Gast
Wenn Sie möchten, können Sie selbst eine vorgeschlagene Änderung vornehmen. (Nach meiner Erfahrung wird es von Rezensenten eher abgelehnt, aber eine klare Erklärung in der Bearbeitungszusammenfassung könnte helfen.) Aber vielleicht war ich in meinem Kommentar zu Ihnen nicht klar ... Ihre Antwort ist eine eigenständige Antwort , ein gutes Update von Matthias 'älterer Antwort. Sie mussten nicht den Text einfügen, der erklärte, dass Sie kommentieren wollten, ist alles. Ich habe die Antwort so bearbeitet, dass Matthias angemessen berücksichtigt wird. Sie müssen nicht mehr tun.
Mogsdad
2

Ein Kommentar zum Skript: git-file-size-diff, vorgeschlagen von patthoyts. Das Skript ist sehr nützlich, ich habe jedoch zwei Probleme gefunden:

  1. Wenn jemand die Berechtigungen für die Datei ändert, gibt git einen anderen Typ in der case-Anweisung zurück:

    T) echo >&2 "Skipping change of type"
    continue ;;
    
  2. Wenn (aus irgendeinem Grund) kein sha-1-Wert mehr vorhanden ist, stürzt das Skript ab. Sie müssen den sha validieren, bevor Sie die Dateigröße erhalten:

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

Die vollständige case-Anweisung sieht dann folgendermaßen aus:

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
quelle