Opcja zwiastunów w opcji git --pretty

Dec 20 2020

Próbowałem wyodrębnić podsumowanie wkładów z dziennika git i stworzyć zwięzłe podsumowanie tego i utworzyć z niego plik excel / csv do prezentowania raportów.

Próbowałem

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

a CSV wygląda jak z pustą kolumną CSV na końcu.

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

i git logwygląda jakoś

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

Nie udało mi się wyodrębnić Differential Revisionciągu za pomocą (trailers:key="Reviewed By")polecenia.

Nie mogłem znaleźć wiele na temat tego, jak to działa. Sprawdziłem podręcznik gita i spróbowałem tego, co wyjaśnia.

Czy jest coś, czego może mi brakować w tym poleceniu? Oczekiwany wynik powinien mieć tekst https://codereviews.com/DD8822na ostatniej pozycji w powyższym wyjściu CVS.

Odpowiedzi

3 fluffy Dec 20 2020 at 20:09

Nie jestem pewien, ale:

  • Klucze przyczepy nie mogą mieć białych znaków (w związku z tym Reviewed By-> Reviewed-Byi Differential Revision-> Differential-Revision);
  • zwiastuny nie powinny być oddzielane nowymi wierszami, ale oddzielone od komunikatu o zatwierdzeniu (dlatego Reviewed Byz twojego pytania nie jest uważany za zwiastun).

Nie polecałbym również używania CSV, ale zamiast tego używam TSV: wyjście git nie jest świadome składni CSV (średniki i przecinki ze znakami ucieczki), dlatego dokument wyjściowy może być generowany jako niemożliwy do przeanalizowania.

Jeśli twoje komunikaty o zmianach wyglądałyby tak ( -zamiast spacji, bez nowych ograniczników linii):

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

Wtedy zadziała dla ciebie następujące polecenie:

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)'

tworzenie identyfikatora krótkiego zatwierdzenia, nazwiska autora, adresu e-mail autora, daty, komunikatu dotyczącego zmiany, zwiastuna Reviewed-Byi zwiastuna Differential-Revisiondo danych wyjściowych wartości rozdzielonych tabulatorami.


Jeśli nie mogą zmienić stary popełnić wiadomości, gdyż historia nie jest bezpieczne dla tej operacji (nie jest to opublikowane, ciągnięty przez rówieśników, Twoje narzędzia są związane z opublikowanymi popełnić skrótów), potem trzeba przetworzyć git logwyjście z sed, awk, perl, lub dowolny inne narzędzie do przekształcania tekstu w celu wygenerowania raportu. Powiedzmy, przetwórz coś takiego, jak git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'gdzie linie między ^B(STX) a EOF powinny być w jakiś sposób przeanalizowane (przefiltrowane pod kątem zwiastunów, które Cię interesują), a następnie dołączone do ich linii grupowych zaczynających się od ^B, a następnie zastąpione znakami, aby zastąpić separatory pól i wpisów z \ti nie znak odpowiednio.

Ale znowu, jeśli możesz edytować historię, naprawiając zwiastuny komunikatów o zmianach (nie jesteś pewien, jak bardzo może to wpłynąć), radziłbym to zrobić, a następnie odrzucić pomysł dodatkowych skryptów przetwarzających zwiastuny, które nie są rozpoznawane przez git-interpret-trailersi po prostu naprawić komunikaty o zmianach.


Edytuj 1 (narzędzia tekstowe)

Jeśli przepisywanie historii nie wchodzi w grę, może pomóc zaimplementowanie niektórych skryptów. Jestem dość słaby w pisaniu potężnych sed/ awk/ perlskryptów, ale pozwól mi spróbować.

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'

Jak to działa:

  • gitgeneruje log złożony z danych rozdzielonych standardowymi kodami C0 C1 przy założeniu, że nie ma takich znaków w twoich komunikatach o zmianach (STX, RS i US - nie wiem, czy to dobre miejsce, aby ich tak używać i czy je zastosuję semantycznie poprawne);
  • gawk filtruje dane wyjściowe dziennika próbując przeanalizować grupy uruchomione przez STX i wyodrębnić zwiastuny, generując „dwuwierszowe” wyjście (każda nieparzysta linia dla zwykłych danych, każda parzysta linia dla wartości końcowych połączonych przecinkami, nawet dla brakujących zwiastunów);
  • sedłączy parami linie nieparzyste i parzyste (kredyty należą do Karoly Horvath );
  • sed usuwa STX i RS;
  • sed zastępuje US na TAB.

Oto trailers.awk(znowu nie jestem awkfacetem i nie mam pojęcia, jak idiomatyczny jest następujący skrypt, ale wydaje się, że działa):

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

Kilka słów, jak awkdziała skrypt:

  • zakłada, że ​​rekordy, które nie wymagają przetwarzania, zaczynają się od STX;
  • próbuje grepznaleźć Key Name: Valuewzorzec w każdej linii innej niż „STX” i zapisuje znaleziony wynik w tymczasowej tablicy TRAILERS(która służy w rzeczywistości jako multimapa, jak Map<String, List<String>>w Javie) dla każdego rekordu;
  • każdy rekord jest zapisywany tak, jak jest, ale zwiastuny są zapisywane albo przed wykryciem nowego rekordu, albo podczas EOF.

Edycja 2 (lepsza awk)

Cóż, jestem naprawdę słaby awk, więc kiedy przeczytałem więcej o awkzmiennych wewnętrznych, doszedłem do wniosku, że awkskrypt można całkowicie zreimplementować i stworzyć gotowy do użycia wynik podobny do TSV bez żadnego przetwarzania końcowego za pomocą sedlub perl. Tak więc krótsza i ulepszona wersja skryptu to:

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

O wiele bardziej zwięzłe, łatwiejsze do odczytania, zrozumienia i utrzymania.