Anhänger Option in Git - hübsche Option

Dec 20 2020

Ich habe versucht, eine Zusammenfassung der Beiträge aus dem Git-Protokoll zu extrahieren, eine kurze Zusammenfassung davon zu erstellen und daraus ein Excel / CSV zu erstellen, um Berichte zu präsentieren.

Ich habe es versucht

git log --after="2020-12-10" --pretty=format:'"%h","%an","%ae","%aD","%s","(trailers:key="Reviewed By")"'

und die CSV sieht aus wie mit einer leeren CSV-Spalte am Ende.

...
"7c87963cc","XYZ","[email protected]","Tue Dec 8 17:40:13 2020 +0000","[TTI] Add support for target hook in compiler.", ""
...

und das git logsieht so aus wie

commit 7c87963cc
Author: XYZ <[email protected]>
Date:   Tue Dec 8 17:40:13 2020 +0000

    [TTI] Add support for target hook in compiler.

    This adds some code in the TabeleGen ...
    This is my body of commit.

    Reviewed By: Sushant

    Differential Revision: https://codereviews.com/DD8822

Was mir nicht gelingen konnte, war das Extrahieren der Differential RevisionZeichenfolge mit dem (trailers:key="Reviewed By")Befehl.

Ich konnte nicht viel darüber finden, wie ich das zum Laufen bringen kann. Ich habe das Git-Handbuch überprüft und versucht, was es erklärt.

Gibt es etwas, das mir in diesem Befehl fehlen könnte? Die erwartete Ausgabe sollte den Text https://codereviews.com/DD8822an der letzten Position in der obigen CVS-Ausgabe haben.

Antworten

3 fluffy Dec 20 2020 at 20:09

Ich bin mir aber nicht sicher:

  • Trailer-Schlüssel dürfen keine Leerzeichen haben (daher Reviewed By-> Reviewed-Byund Differential Revision-> Differential-Revision);
  • Trailer sollten nicht durch neue Zeilen begrenzt, sondern von der Commit-Commit-Nachricht getrennt werden (daher wird Reviewed ByIhre Frage nicht als Trailer betrachtet).

Ich würde auch nicht empfehlen, CSV zu verwenden, sondern stattdessen TSV: Die Git-Ausgabe kennt die CSV-Syntax nicht (Semikolons und Kommas werden ausgeblendet), daher wird das Ausgabedokument möglicherweise nicht analysierbar generiert.

Wenn Ihre Commit-Nachrichten so aussehen würden ( -anstelle von Leerzeichen keine neuen Zeilenbegrenzer):

commit 7c87963cc
Author: XYZ <[email protected]>
Date:   Tue Dec 8 17:40:13 2020 +0000

    [TTI] Add support for target hook in compiler.

    This adds some code in the TabeleGen ...
    This is my body of commit.

    Reviewed-By: Sushant
    Differential-Revision: https://codereviews.com/DD8822

Dann würde der folgende Befehl für Sie funktionieren:

git log --pretty=format:'%h%x09%an%x09%ae%x09%aD%x09%s%x09%(trailers:key=Reviewed-By,separator=%x20,valueonly)%x09%(trailers:key=Differential-Revision,separator=%x20,valueonly)'

Erstellen einer kurzen Festschreibungs-ID, eines Autorennamens, einer E-Mail-Adresse des Autors, eines Datums, einer Festschreibungsnachricht, eines Trailers Reviewed-Byund eines Trailers Differential-Revisionfür Ihre durch Tabulatoren getrennte Werte.


Wenn Sie nicht die alten Nachrichten begehen kann sich ändern , weil Ihre Geschichte nicht sicher ist , dies zu tun (es ist veröffentlicht, von Kollegen gezogen, Ihre Werkzeuge sind auf die veröffentlichten verpflichten Hashes gebunden ist ), dann müssen Sie den Prozess - git logAusgang mit sed, awk, perloder jede anderes Texttransformationswerkzeug zum Generieren Ihres Berichts. Verarbeiten Sie beispielsweise, git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'wo Linien zwischen ^B(STX) und EOF irgendwie analysiert werden sollten (gefiltert nach den Anhängern, an denen Sie interessiert sind), dann beginnend mit ihren Gruppenlinien verbunden ^Bwerden und dann das Zeichen ersetzt werden, um Feld- und Eintragstrennzeichen durch \tund nein zu ersetzen Zeichen jeweils.

Wenn Sie jedoch den Verlauf bearbeiten können, indem Sie Commit-Nachrichten-Trailer reparieren (nicht sicher, wie stark sich dies auswirken kann), würde ich Ihnen empfehlen, dies zu tun und dann die Idee von zusätzlichen Skripten, die Trailer verarbeiten, die von nicht erkannt werden, abzulehnen git-interpret-trailersund einfach die zu reparieren Nachrichten festschreiben.


Bearbeiten 1 (Textwerkzeuge)

Wenn das Umschreiben des Verlaufs nicht möglich ist, kann die Implementierung einiger Skripte hilfreich sein. Ich bin mir ziemlich schwach auf das Schreiben mächtig sed/ awk/ perlSkripte, aber lassen Sie mich versuchen.

git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B' \
    | gawk -f trailers.awk \
    | sed '$!N;s/\n/\x1F/' \
    | sed 's/[\x02\x1E]//g' \
    | sed 's/\x1F/\x09/g'

Wie es funktioniert:

  • gitgeneriert ein Protokoll aus Daten, die mit Standard- C0-C1-Codes abgegrenzt sind, vorausgesetzt, Ihre Commit-Nachrichten enthalten keine solchen Zeichen (STX, RS und US - ich weiß nicht wirklich, ob es ein guter Ort ist, sie so zu verwenden, und ob ich sie anwende semantisch korrekt);
  • gawk filtert die Protokollausgabe, die versucht, STX-gestartete Gruppen zu analysieren und die Trailer zu extrahieren, wodurch eine "zweireihige" Ausgabe generiert wird (jede ungerade Zeile für reguläre Daten, jede gerade Zeile für durch Kommas verbundene Trailerwerte, selbst für fehlende Trailer);
  • sedverbindet ungerade und gerade Linien paarweise (Credits gehen an Karoly Horvath );
  • sed entfernt STX und RS;
  • sed ersetzt US durch TAB.

Hier ist das trailers.awk(wieder bin ich kein awkTyp und habe keine Ahnung, wie idiomatisch das folgende Skript ist, aber es scheint zu funktionieren):

#!/usr/bin/awk -f

BEGIN {
    FIRST = 1
    delete TRAILERS
}

function print_joined_array(array) {
    if ( !length(array) ) {
        return
    }
    for ( i in array ) {
        if ( i > 0 ) {
            printf(",")
        }
        printf("%s", array[i])
    }
    printf("\x1F")
}

function print_trailers() {
    if ( FIRST ) {
        FIRST = 0
        return
    }
    print_joined_array(TRAILERS["Reviewed By"])
    print_joined_array(TRAILERS["Differential Revision"])
    print ""
}

/^\x02/ {
    print_trailers()
    print $0
    delete TRAILERS
}

match($0, /^([-_ A-Za-z0-9]+):\s+(.*)\s*/, M) {
    TRAILERS[M[1]][length(TRAILERS[M[1]])] = M[2]
}

END {
    print_trailers()
}

Ein paar Worte, wie das awkSkript funktioniert:

  • Es wird davon ausgegangen, dass Datensätze, die nicht verarbeitet werden müssen, mit STX beginnen.
  • Es versucht, für grepjedes Key Name: ValueMuster in jeder Nicht-STX-Zeile ein Muster zu finden und speichert das gefundene Ergebnis für jeden Datensatz in einem temporären Array TRAILERS(das tatsächlich als Multimap dient, wie Map<String, List<String>>in Java).
  • Jeder Datensatz wird so geschrieben, wie er ist, aber Trailer werden entweder vor dem Erkennen eines neuen Datensatzes oder bei EOF geschrieben.

Edit 2 (besser awk)

Nun, ich bin sehr schwach darin. awkNachdem ich mehr über awkinterne Variablen gelesen hatte , stellte ich fest, dass das awkSkript vollständig neu implementiert werden kann und eine gebrauchsfertige TSV-ähnliche Ausgabe selbst ohne Nachbearbeitung mit sedoder erzeugt werden kann perl. Die kürzere und verbesserte Version des Skripts lautet also:

#!/bin/bash

git log --pretty=format:'%x1E%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%B%x1E' \
    | gawk -f trailers.awk
#!/usr/bin/awk -f

BEGIN {
    RS = "\x1E"
    FS = "\x1F"
    OFS = "\x09"
}

function extract(array, trailer_key, __buffer) {
    for ( i in array ) {
        if ( index(array[i], trailer_key) > 0 ) {
            if ( length(__buffer) > 0 ) {
                __buffer = __buffer ","
            }
            __buffer = __buffer substr(array[i], length(trailer_key))
        }
    }
    return __buffer
}

NF > 1 {
    split($6, array, "\n")
    print $1, $2, $3, $4, $5, extract(array, "Reviewed By: "), extract(array, "Differential Revision: ")
}

Viel prägnanter, leichter zu lesen, zu verstehen und zu warten.