Git: Filenamen über Pipe annehemen



  • Ich möchte mir mit Hilfe von Git ausgeben lassen welcher Autor wie viele Zeilen zuletzt im Repo geändert hat.

    Ich gebe dazu folgendes Kommando ein:

    ls **/*.txt | xargs git blame --line-porcelain | sed -n 's/^author //p' | sort | uniq -c | sort -rn
    

    `ls **/.txt` ist in zsh mehr oder weniger äquivalent zu `find . -name ".txt"`. Als Fehlermeldung erhalte ich

    fatal: bad revision 'filename.txt'
    

    Wenn ich aber direkt

    git blame --line-porcelain filename.txt | sed -n 's/^author //p' | sort | uniq -c | sort -rn
    

    eingebe bekomme ich das gewünschte Ergebnis. Kann mir jemand sagen warum Git den Filenamen über eine Pipe nicht annimmt?



  • Darf ich fragen, was der Unterschied zwischen

    ls **/*.txt | xargs git blame --line-porcelain
    

    und

    git blame --line-porcelain **/*.txt
    

    ist?



  • Da gibt es keinen Unterschied, das hatte ich gerade auch herausgefunden. Funktioniert leider trotzdem nicht, bekomme die gleiche Fehlermeldung.



  • Antoras schrieb:

    eingebe bekomme ich das gewünschte Ergebnis. Kann mir jemand sagen warum Git den Filenamen über eine Pipe nicht annimmt?

    Git bekommt in deinem Beispiel überhaupt nichts über eine Pipe. Weder über eine als Stdin geerbte, noch über eine benannte im Dateisystem.

    Genau der Umstand, dass nicht alle Programme ihren Input auch von einem FD lesen können ist doch praktisch die Existenzberechtigung für xargs.

    Was xargs macht, ist in etwa folgendes:
    1. eine bestimmte Anzahl whitespace-getrennte Worte von Stdin lesen.
    2. die übergebene Cmdline (bei dir git blame...) ausführen mit den zuletzt gelesenen Worten als argv
    3. wiederhole bis EOF

    Dein Problem liegt aber sowieso ganz woanders. Probier mal aus:

    git blame file1 file2
    

    😉



  • Ok, das heißt xargs führt das entsprechende Programm nicht für jede gelesene Zeile aus sondern übergibt alle Zeilen als Parameter an das entsprechende Programm, welches dann damit klar kommen muss? Dann macht auch die Fehlermeldung Sinn.

    Ich habe mein Skript mal abgeändert:

    for f in **/*.txt; do g bl --line-porcelain $f; done | sed -n 's/^author //p' | sort | uniq -c | sort -rn
    

    Dauert nur ~30s auf meinem Repo. Ka ob man da etwas verbessern kann.



  • Antoras schrieb:

    Ok, das heißt xargs führt das entsprechende Programm nicht für jede gelesene Zeile aus sondern übergibt alle Zeilen als Parameter an das entsprechende Programm, welches dann damit klar kommen muss? Dann macht auch die Fehlermeldung Sinn.

    xargs unterteilt in Gruppen die klein genug sind, dass normale Tools damit auskommen. Git muss aber immer noch mehrere Files auf einmal als Parameter akzeptieren.

    for f in **/*.txt; do g bl --line-porcelain $f; done | sed -n 's/^author //p' | sort | uniq -c | sort -rn
    

    Dauert nur ~30s auf meinem Repo. Ka ob man da etwas verbessern kann.

    Warum nicht einfach direkt mit find?

    find . -name '*.sh' -exec g bl --line-porcelain {} \; | sed -n 's/^author //p' | sort | uniq -c | sort -rn
    


  • Dafür hat mein sh-foo nicht ausgereicht, jetzt ist es gerade gestiegen. 😉

    Vielen Dank für deine Hilfe.


Log in to reply