Option remorques dans git - optionpretty

Dec 20 2020

J'essayais d'extraire un résumé des contributions de git log et d'en créer un résumé concis et d'en créer un excel / csv pour présenter des rapports.

J'ai essayé

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

et le CSV ressemble à une colonne CSV vide à la fin.

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

et le git logressemble à quelque chose comme

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

Ce que je ne pouvais pas réussir, c'était d'extraire la Differential Revisionchaîne à l'aide de la (trailers:key="Reviewed By")commande.

Je n'ai pas trouvé grand-chose sur la façon de faire fonctionner cela. J'ai vérifié le manuel de git et j'ai essayé ce qu'il explique.

Y a-t-il quelque chose qui me manque peut-être dans cette commande? La sortie attendue doit avoir le texte https://codereviews.com/DD8822à la dernière position dans la sortie CVS ci-dessus.

Réponses

3 fluffy Dec 20 2020 at 20:09

Je ne suis pas sûr mais:

  • les clés de fin ne peuvent pas avoir d'espaces (donc Reviewed By-> Reviewed-Byet Differential Revision-> Differential-Revision);
  • les bandes-annonces ne doivent pas être délimitées par de nouvelles lignes, mais séparées du message de validation de validation (par conséquent, Reviewed Byvotre question n'est pas considérée comme une bande-annonce).

Je ne recommanderais pas non plus d'utiliser CSV, mais d'utiliser TSV à la place: la sortie git n'est pas consciente de la syntaxe CSV (les points-virgules et les virgules s'échappant), par conséquent, le document de sortie peut être généré de manière non analysable.

Si vos messages de validation ressemblent à ceci ( -au lieu d'espaces, pas de nouveaux délimiteurs de ligne):

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

Ensuite, la commande suivante fonctionnerait pour vous:

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

produire un identifiant de validation court, le nom de l'auteur, l'adresse e-mail de l'auteur, la date, le message de validation, la bande Reviewed-By-annonce et la bande-annonce Differential-Revisiondans votre sortie de valeurs séparées par des tabulations


Si vous ne pouvez pas changer l'ancien commits parce que votre histoire n'est pas sûr pour ce faire (il est publié, tiré par les pairs, vos outils sont liés aux publiés commettre hash), alors vous devez traiter la git logsortie avec sed, awk, perlou tout autre outil de transformation de texte pour générer votre rapport. Dites, traitez quelque chose comme git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'où les lignes entre ^B(STX) et EOF devraient être analysées d'une manière ou d'une autre (filtrées pour les bandes-annonces qui vous intéressent), puis jointes à leurs lignes de groupe en commençant par ^B, puis le caractère remplacé pour remplacer les séparateurs de champ et d'entrée par \tet non caractère respectivement.

Mais encore une fois, si vous pouvez modifier l'historique en corrigeant les bandes-annonces de messages de validation (je ne sais pas dans quelle mesure cela peut affecter), je vous recommande de le faire, puis de rejeter l'idée de scripts supplémentaires traitant les bandes-annonces qui ne sont pas reconnues par git-interpret-trailerset de simplement corriger le commettre des messages.


Modifier 1 (outils de texte)

Si la réécriture de l'historique n'est pas une option, l'implémentation de certains scripts peut vous aider. Je suis assez faible pour écrire des scripts / sed/ puissants , mais laissez-moi essayer.awkperl

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'

Comment ça fonctionne:

  • gitgénère un journal composé de données délimitées avec des codes C0 C1 standard en supposant qu'il n'y a pas de tels caractères vos messages de validation (STX, RS et US - je ne sais pas vraiment si c'est un bon endroit pour les utiliser comme ça et si je les applique sémantiquement correct);
  • gawk filtre la sortie du journal en essayant d'analyser les groupes démarrés par STX et d'extraire les remorques, générant une sortie «à deux rangées» (chaque ligne impaire pour les données régulières, chaque ligne paire pour les valeurs de fin de fin jointes par des virgules même pour les remorques manquantes);
  • sedjoint les lignes paires et impaires par paires (les crédits reviennent à Karoly Horvath );
  • sed supprime STX et RS;
  • sed remplace US par TAB.

Voici le trailers.awk(encore une fois, je ne suis pas un awkgars et je n'ai aucune idée à quel point le script suivant est idiomatique, mais cela semble fonctionner):

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

Quelques mots sur le fonctionnement du awkscript:

  • il suppose que les enregistrements qui ne nécessitent pas de traitement commencent par STX;
  • il essaie sur grepchaque ligne non "STX" un Key Name: Valuemotif et enregistre le résultat trouvé dans un tableau temporaire TRAILERS(qui sert en fait de multi-carte, comme Map<String, List<String>>en Java) pour chaque enregistrement;
  • chaque enregistrement est écrit tel quel, mais les bandes-annonces sont écrites soit avant la détection d'un nouvel enregistrement, soit à l'EOF.

Edit 2 (mieux awk)

Eh bien, je suis vraiment faible awk, donc une fois que j'ai lu plus sur awkles variables internes, j'ai compris que le awkscript pouvait être entièrement réimplémenté et produire lui-même une sortie de type TSV prête à l'emploi sans aucun post-traitement avec sedou perl. La version plus courte et améliorée du script est donc:

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

Beaucoup plus concis, plus facile à lire, à comprendre et à maintenir.