Git'te treyler seçeneği - güzel seçeneği

Dec 20 2020

Git log'dan katkıların bir özetini çıkarmaya ve bunun kısa bir özetini oluşturmaya ve raporları sunmak için ondan bir excel / csv oluşturmaya çalışıyordum.

Denedim

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

ve CSV, sonunda boş bir CSV sütunu gibi görünür.

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

ve bir git logşeye benziyor

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

Başarılı olamadığım şey Differential Revision, (trailers:key="Reviewed By")komutu kullanarak dizeyi ayıklamaktı .

Bunu nasıl çalıştıracağım konusunda pek bir şey bulamadım. Git kılavuzunu kontrol ettim ve açıkladığını denedim.

Bu komutta eksik olabileceğim bir şey var mı? Beklenen çıktı https://codereviews.com/DD8822, yukarıdaki CVS çıktısının son konumunda metne sahip olmalıdır .

Yanıtlar

3 fluffy Dec 20 2020 at 20:09

Emin değilim ama:

  • römork anahtarlarının boşlukları olamaz (bu nedenle Reviewed By-> Reviewed-Byve Differential Revision-> Differential-Revision);
  • fragmanlar yeni satırlarla sınırlandırılmamalı, ancak commit commit mesajından ayrılmalıdır (bu nedenle Reviewed Bysorunuzdan fragman olarak kabul edilmez).

CSV kullanılmasını da önermem, bunun yerine TSV kullanılmasını tavsiye ederim: git output, CSV sözdiziminin farkında değil (noktalı virgül ve virgül kaçış), bu nedenle çıktı belgesi ayrıştırılamaz şekilde oluşturulabilir.

Kaydetme mesajlarınız şöyle görünüyorsa ( -boşluk yerine, yeni satır sınırlayıcı yok):

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 zaman aşağıdaki komut sizin için çalışacaktır:

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

sekmeyle ayrılmış değerler çıktınıza kısa kaydetme kimliği, yazar adı, yazar e-postası, tarih, yürütme mesajı, fragman Reviewed-Byve fragman üretme Differential-Revision.


Eğer tarih (o, yaşıtları tarafından çekilen, Yayınlandıktan araçlarınız işlemek yayınlanan sağlamalarının bağlıdırlar) bu iş için güvenli olmadığı için eski mesajları işlemek değiştiremez, o zaman işlemek zorunda git logçıkışı ile sed, awk, perlherhangi bir ya da Raporunuzu oluşturmak için başka bir metin dönüştürme aracı. Diyelim ki, (STX) ve EOF git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B'arasındaki satırların bir ^Bşekilde analiz edilmesi (ilgilendiğiniz fragmanlar için filtrelenmesi), ardından ile başlayan grup satırlarına katılması ^Bve ardından alan ve giriş ayırıcılarını değiştirmek için karakter değiştirmesi \tve hayır sırasıyla karakter.

Ancak yine de, kaydetme mesajı fragmanlarını düzelterek geçmişi düzenleyebilirseniz (bunun ne kadar etkileyebileceğinden emin değilseniz), bunu yapmanızı ve ardından, fragmanları işleyen ekstra komut dosyaları fikrini reddetmenizi git-interpret-trailersve basitçe düzeltmenizi öneririm . mesajları işlemek.


Düzenleme 1 (metin araçları)

Geçmişi yeniden yazmak bir seçenek değilse, bazı komut dosyalarını uygulamak size yardımcı olabilir. Güçlü sed/ awk/ perlsenaryolar yazmada oldukça zayıfım , ama deneyeyim.

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'

Nasıl çalışır:

  • gitKaydetme mesajlarınızda (STX, RS ve US) böyle bir karakter olmadığını varsayarak standart C0 C1 kodlarıyla sınırlandırılmış verilerden oluşan bir günlük oluşturur (STX, RS ve US - bunları böyle kullanmak için iyi bir yer olup olmadığını ve bunları uygularsam gerçekten bilmiyorum anlamsal olarak doğru);
  • gawk STX ile başlatılan grupları ayrıştırmaya ve römorkları çıkarmaya çalışırken günlük çıktısını filtreler, "iki sıralı" çıktı (normal veriler için her tek satır, eksik römorklar için bile virgülle birleştirilmiş römork değerleri için her çift satır);
  • sedçiftler halinde tek ve çift satırları birleştirir (krediler Karoly Horvath'a gider );
  • sed STX ve RS'yi kaldırır;
  • sed US'nin yerini TAB ile değiştirir.

İşte trailers.awk(yine bir awkerkek değilim ve aşağıdaki komut dosyasının ne kadar deyimsel olduğu hakkında hiçbir fikrim yok, ama işe yarıyor gibi görünüyor):

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

awkSenaryonun nasıl çalıştığı birkaç kelime :

  • işlem gerektirmeyen kayıtların STX ile başladığını varsayar;
  • grepbir Key Name: Valuemodel için "STX" olmayan her satıra çalışır ve bulunan sonucu her kayıt için geçici bir diziye TRAILERS(Java'da olduğu gibi aslında bir çoklu harita olarak hizmet eder Map<String, List<String>>) kaydeder;
  • her kayıt olduğu gibi yazılır, ancak fragmanlar ya yeni bir kayıt tespit edilmeden önce ya da EOF'de yazılır.

Edit 2 (daha iyi awk)

Şey, gerçekten zayıfım awk, bu yüzden awkdahili değişkenler hakkında daha fazla okuduğumda , awkbetiğin tamamen yeniden uygulanabileceğini ve sedveya ile herhangi bir son işlem yapmadan TSV benzeri bir çıktı üretebileceğini anladım perl. Yani betiğin daha kısa ve geliştirilmiş versiyonu şu şekildedir:

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

Çok daha kısa, okunması, anlaşılması ve bakımı daha kolay.