Opção de trailers em git --pretty option
Eu estava tentando extrair um resumo das contribuições do git log e criar um resumo conciso disso e criar um excel / csv a partir dele para apresentar relatórios.
Eu tentei
git log --after="2020-12-10" --pretty=format:'"%h","%an","%ae","%aD","%s","(trailers:key="Reviewed By")"'
e o CSV se parece com uma coluna CSV em branco no final.
...
"7c87963cc","XYZ","[email protected]","Tue Dec 8 17:40:13 2020 +0000","[TTI] Add support for target hook in compiler.", ""
...
e git logparece algo como
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
O que não consegui foi extrair a Differential Revisionstring usando o (trailers:key="Reviewed By")comando.
Não consegui descobrir muito sobre como fazer isso funcionar. Eu verifiquei o manual do git e tentei o que ele explica.
Existe algo que eu possa estar faltando neste comando? A saída esperada deve ter o texto https://codereviews.com/DD8822na última posição na saída CVS acima.
Respostas
Não tenho certeza, mas:
- as chaves do trailer não podem ter espaços em branco (portanto
Reviewed By->Reviewed-ByeDifferential Revision->Differential-Revision); - trailers não devem ser delimitados por novas linhas, mas separados da mensagem de commit commit (portanto,
Reviewed Bysua pergunta não é considerada um trailer).
Eu também não recomendaria o uso de CSV, mas sim de TSV: a saída git não reconhece a sintaxe CSV (ponto-e-vírgula e escape de vírgula), portanto, o documento de saída pode ser gerado de forma não analisável.
Se suas mensagens de confirmação forem parecidas com esta (em -vez de espaços, sem novos delimitadores de linha):
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
Então, o seguinte comando funcionaria para você:
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)'
produzindo ID de commit curto, nome do autor, e-mail do autor, data, mensagem de commit, trailer Reviewed-Bye trailer Differential-Revisionpara sua saída de valores separados por tabulação.
Se você não pode mudar o velho cometer mensagens porque seu histórico não é seguro para fazer isso (ele é publicado, puxado por seus pares, suas ferramentas são ligados aos hashes publicados commit), então você tem que processar a git logsaída com sed, awk, perlou qualquer outra ferramenta de transformação de texto para gerar seu relatório. Digamos, processe algo como git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'onde as linhas entre ^B(STX) e EOF devem ser analisadas de alguma forma (filtradas para os trailers nos quais você está interessado), em seguida, unidas às linhas do grupo começando com ^Be, em seguida, caracteres substituídos para substituir os separadores de campo e entrada por \te não personagem respectivamente.
Mas, novamente, se você pode editar o histórico corrigindo trailers de mensagem de commit (não tenho certeza de quanto isso pode afetar), eu recomendo que você faça isso e rejeite a ideia de scripts extras de processamento de trailers que não são reconhecidos git-interpret-trailerse simplesmente consertem o enviar mensagens.
Editar 1 (ferramentas de texto)
Se reescrever o histórico não for uma opção, a implementação de alguns scripts pode ajudá-lo. Sou muito fraco para escrever scripts / sed/ poderosos , mas deixe-me tentar.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'
Como funciona:
gitgera um log feito de dados delimitados com códigos C0 C1 padrão assumindo que não existem tais caracteres suas mensagens de commit (STX, RS e US - eu realmente não sei se é um bom lugar para usá-los assim e se eu os aplico semanticamente correto);gawkfiltra a saída de log tentando analisar grupos iniciados por STX e extrair os trailers, gerando uma saída de "duas linhas" (cada linha ímpar para dados regulares, cada linha par para valores de trailer unidos por vírgula, mesmo para trailers ausentes);sedjunta linhas pares e ímpares (os créditos vão para Karoly Horvath );sedremove STX e RS;sedsubstitui US por TAB.
Aqui está o trailers.awk(novamente eu não sou um awkcara e não tenho ideia de como o script a seguir é idiomático, mas parece funcionar):
#!/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()
}
Algumas palavras sobre como o awkscript funciona:
- ele assume que os registros que não requerem processamento estão começando com STX;
- ele tenta
grepcada linha não "STX" para umKey Name: Valuepadrão e salva o resultado encontrado em um array temporárioTRAILERS(que serve na verdade como um multimapa, comoMap<String, List<String>>em Java) para cada registro; - cada registro é escrito como está, mas os trailers são escritos antes de detectar um novo registro ou no EOF.
Editar 2 (melhor awk)
Bem, sou muito fraco em awk, então, depois de ler mais sobre awkvariáveis internas, descobri que o awkscript pode ser totalmente reimplementado e produzir uma saída tipo TSV pronta para usar sem qualquer pós-processamento com sedou perl. Portanto, a versão mais curta e aprimorada do script é:
#!/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: ")
}
Muito mais conciso, fácil de ler, entender e manter.