Opsi cuplikan dalam opsi git --pretty

Dec 20 2020

Saya mencoba mengekstrak ringkasan kontribusi dari git log dan membuat ringkasan singkat tentang itu dan membuat excel / csv darinya untuk menyajikan laporan.

Saya sudah mencoba

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

dan CSV tampak seperti kolom CSV kosong di bagian akhir.

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

dan git logterlihat seperti itu

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

Apa yang saya tidak bisa berhasil adalah mengekstrak Differential Revisionstring menggunakan (trailers:key="Reviewed By")perintah.

Saya tidak dapat menemukan banyak tentang bagaimana membuat ini bekerja. Saya memeriksa manual git dan saya mencoba apa yang dijelaskannya.

Apakah ada sesuatu yang mungkin saya lewatkan dalam perintah ini? Keluaran yang diharapkan harus memiliki teks https://codereviews.com/DD8822pada posisi terakhir dalam keluaran CVS di atas.

Jawaban

3 fluffy Dec 20 2020 at 20:09

Saya tidak yakin tapi:

  • kunci trailer tidak boleh memiliki spasi putih (oleh karena itu Reviewed By-> Reviewed-By, dan Differential Revision-> Differential-Revision);
  • cuplikan tidak boleh dibatasi oleh baris baru, tetapi dipisahkan dari pesan komit komit (oleh karena itu Reviewed Bydari pertanyaan Anda tidak dianggap sebagai cuplikan).

Saya juga tidak akan merekomendasikan menggunakan CSV, tetapi menggunakan TSV sebagai gantinya: keluaran git tidak mengetahui sintaks CSV (titik koma dan pelolosan koma), oleh karena itu dokumen keluaran dapat dihasilkan tidak dapat diuraikan.

Jika pesan komit Anda akan terlihat seperti ini ( -bukan spasi, tidak ada pembatas baris baru):

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

Maka perintah berikut akan bekerja untuk Anda:

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

menghasilkan id komit pendek, nama penulis, email penulis, tanggal, pesan komit, cuplikan Reviewed-By, dan cuplikan Differential-Revisionke keluaran nilai yang dipisahkan tab Anda.


Jika Anda tidak dapat mengubah lama pesan komit karena sejarah Anda tidak aman untuk melakukan hal ini (itu diterbitkan, ditarik oleh rekan-rekan, alat Anda terikat untuk hash diterbitkan komit), maka Anda harus memproses git logoutput dengan sed, awk, perl, atau alat pengubah teks lainnya untuk menghasilkan laporan Anda. Katakanlah, proses sesuatu seperti di git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'mana garis antara ^B(STX) dan EOF harus dianalisis entah bagaimana (difilter untuk trailer yang Anda minati), lalu bergabung dengan garis grup mereka yang dimulai dengan ^B, dan kemudian karakter diganti untuk mengganti pemisah bidang dan entri dengan \tdan tidak karakter masing-masing.

Tetapi sekali lagi, jika Anda dapat mengedit riwayat dengan memperbaiki cuplikan pesan komit (tidak yakin seberapa besar pengaruhnya), saya sarankan Anda melakukannya dan kemudian menolak gagasan trailer pemrosesan skrip tambahan yang tidak dikenali oleh git-interpret-trailersdan hanya memperbaiki melakukan pesan.


Edit 1 (alat teks)

Jika menulis ulang sejarah bukanlah suatu pilihan, maka menerapkan beberapa skrip dapat membantu Anda. Aku cukup lemah dalam menulis skrip / sed/ yang kuat , tapi biarkan aku mencobanya.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'

Bagaimana itu bekerja:

  • gitmenghasilkan log yang terbuat dari data yang dibatasi dengan kode C0 C1 standar dengan asumsi tidak ada karakter seperti itu pada pesan komit Anda (STX, RS dan AS - saya tidak begitu tahu apakah itu tempat yang baik untuk menggunakannya seperti itu dan jika saya menerapkannya benar secara semantik);
  • gawk memfilter keluaran log yang mencoba mengurai grup yang dimulai STX dan mengekstrak cuplikannya, menghasilkan keluaran "dua baris" (setiap baris ganjil untuk data biasa, setiap baris genap untuk nilai cuplikan yang digabungkan koma, bahkan untuk cuplikan yang hilang);
  • sedmenggabungkan garis ganjil dan genap secara berpasangan (kredit diberikan ke Karoly Horvath );
  • sed menghapus STX dan RS;
  • sed menggantikan AS ke TAB.

Ini dia trailers.awk(sekali lagi saya bukan awklaki - laki dan tidak tahu betapa idiomatisnya skrip berikut ini, tetapi tampaknya berfungsi):

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

Beberapa kata tentang cara kerja awkskrip:

  • ini mengasumsikan bahwa rekaman yang tidak memerlukan pemrosesan dimulai dengan STX;
  • ia mencoba untuk grepsetiap baris non- "STX" untuk sebuah Key Name: Valuepola dan menyimpan hasil yang ditemukan ke array sementara TRAILERS(yang sebenarnya berfungsi sebagai multimap, seperti Map<String, List<String>>di Java) untuk setiap record;
  • setiap catatan ditulis apa adanya, tetapi cuplikan ditulis sebelum mendeteksi catatan baru atau di EOF.

Edit 2 (lebih baik awk)

Yah, saya benar-benar lemah awk, jadi setelah saya membaca lebih lanjut tentang awkvariabel internal, saya menemukan awkskrip dapat diimplementasikan kembali sepenuhnya dan menghasilkan output seperti TSV yang siap digunakan itu sendiri tanpa pemrosesan pasca dengan sedatau perl. Jadi versi skrip yang lebih pendek dan lebih baik adalah:

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

Jauh lebih ringkas, lebih mudah dibaca, dipahami, dan dipelihara.