Das Festschreibungsprotokoll für eine bestimmte Zeile in einer Datei abrufen?

503

Gibt es eine Möglichkeit, git dazu zu bringen, Ihnen ein Festschreibungsprotokoll für nur Festschreibungen zu geben, die eine bestimmte Zeile in einer Datei berührt haben ?

Wie git blameaber git blamewerden Sie die letzten COMMIT , dass eine bestimmte Linie berühren.

Ich möchte wirklich ein ähnliches Protokoll erhalten, nicht die Liste der Commits an einer beliebigen Stelle in der Datei, sondern nur die Commits, die eine bestimmte Zeile berührt haben.

jrochkind
quelle
2
Siehe auch: Git Schuld - vorherige Commits
joeytwiddle

Antworten:

632

Siehe auch Git: Entdecken Sie, welche Commits jemals eine Reihe von Zeilen berührt haben .


Da Git 1.8.4 , git loghat -Ldie Entwicklung einer Reihe von Linien zu sehen.

Angenommen, Sie sehen sich git blamedie Ausgabe an. Hier -L 150,+11bedeutet "nur die Zeilen 150 bis 150 + 11 betrachten":

$ git blame -L 150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &

Und Sie möchten die Geschichte der heutigen Zeile 155 kennenlernen.

Dann verwenden git log. Hier -L 155,155:git-web--browse.shbedeutet "Verfolgen Sie die Entwicklung der Zeilen 155 bis 155 in der genannten Datei git-web--browse.sh".

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <[email protected]>

    web--browse: support opera, seamonkey and elinks

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -143,1 +143,1 @@
-firefox|iceweasel)
+firefox|iceweasel|seamonkey|iceape)

commit a180055a47c6793eaaba6289f623cff32644215b
Author: Giuseppe Bilotta <[email protected]>

    web--browse: coding style

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -142,1 +142,1 @@
-    firefox|iceweasel)
+firefox|iceweasel)

commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <[email protected]>

    Rename 'git-help--browse.sh' to 'git-web--browse.sh'.

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+    firefox|iceweasel)
Matt McClure
quelle
2
'git log --topo-order --graph -u -L 155,155: git-web--browse.sh' - Dies hat einen schwerwiegenden Fehler verursacht: 'ungültiger Objektname 155,155'. Git-Version: 1.8.3.2. Irgendwelche Vorschläge?
BairDev
12
Upgrade auf Git 1.8.4 oder höher.
Matt McClure
4
Was ist, wenn ich "die Geschichte von Zeile 155 in commitA" (anstelle von Zeile 155 in HEAD) wissen möchte? Kann ich einfach benutzen git log commitA-hash -L 155,155:file-name?
Ida
@Flimm, ich habe keine starke Präferenz.
Matt McClure
Dies funktioniert gut, außer wenn die Datei verschoben / umbenannt wurde ... es scheint, dass --follow nicht gerne mit Zeilenbereichsargumenten kombiniert wird.
Mike Ellery
66

Mit pick-ax können Sie eine Reihe von Commits abrufen.

git log -S'the line from your file' -- path/to/your/file.txt

Dadurch erhalten Sie alle Commits, die diesen Text in dieser Datei betroffen haben. Wenn die Datei irgendwann umbenannt wurde, können Sie --follow-parent hinzufügen.

Wenn Sie die Commits bei jeder dieser Änderungen überprüfen möchten, können Sie dieses Ergebnis an git show weiterleiten:

git log ... | xargs -n 1 git show
Adam Dymitruk
quelle
5
Ich bin mir nicht sicher, wie das hilft. Wenn der Text betroffen war, ist die Zeile nicht mehr dieselbe, sodass die Spitzhacke nur die letzte Änderung anzeigt. Sie müssten dann tun git log -S'the previous version of the line'und so weiter, genau wie Sie es am Ende tun würden git blame -L. Und es wird viel langsamer sein als git blame, da es überall nach dem Text suchen muss, nicht nur an der gegebenen Stelle.
Cascabel
Sie können dort einen regulären Ausdruck verwenden, um die Akzeptanz zu erhöhen. Derzeit gibt es keine Möglichkeit, ohne aufwändige Skripterstellung in der Vergangenheit durch Patches zu navigieren. Ich hoffe, dass gitk diese Funktionalität in Zukunft in seiner Patch-Ansicht erhält.
Adam Dymitruk
3
Warum heißt das Spitzhacke ? :)
Ciprian Tomoiagă
43

Versuchen Sie es mit dem folgenden Befehl, der in Git 1.8.4 implementiert ist.

git log -u -L <upperLimit>,<lowerLimit>:<path_to_filename>

Also, in deinem Fall upperLimit& lowerLimitist das berührtline_number

Weitere Informationen - https://www.techpurohit.com/list-some-useful-git-commands

Jitendrapurohit
quelle
2
Ich denke, --pretty=shortwird bei der Verwendung ignoriert -L. Bitte korrigieren
Vic Seedoubleyew
14

Eine extrem einfache Möglichkeit, dies zu tun, ist die Verwendung von vim-fugitive . Öffnen Sie einfach die Datei in vim, wählen Sie die Zeile (n) aus, die Sie verwenden möchten V, und geben Sie sie ein

:Glog

Jetzt können Sie alle Revisionen der Datei verwenden :cnextund :cprevanzeigen, in der diese Zeile geändert wurde. Geben Sie jederzeit ein, um :Gblamedie Informationen zu sha, Autor und Datum anzuzeigen.

Cory Klein
quelle
13

Vereinfachung der Antwort von @ matt -

git blame -L14,15 -- <file_path>

Hier werden Sie für eine Linie verantwortlich gemacht 14 to 15.

Da die -LOption Rangeals Parameter erwartet, können wir Blamemit der -LOption keine für eine einzelne Zeile erhalten .

Referenz

Swaps
quelle
10

Ich glaube nicht, dass dafür etwas eingebaut ist. Die Tatsache, dass sich eine einzelne Zeile selten mehrmals ändert, ohne dass sich auch der Rest der Datei wesentlich ändert, macht es schwierig, sodass sich die Zeilennummern häufig stark ändern.

Wenn Sie das Glück haben, dass die Zeile immer ein identifizierendes Merkmal aufweist, z. B. eine Zuordnung zu einer Variablen, deren Name sich nie geändert hat, können Sie die Regex-Option für verwenden git blame -L. Zum Beispiel:

git blame -L '/variable_name *= */',+1

Dies findet aber nur den ersten Übereinstimmung für diesen regulären Ausdruck. Wenn Sie also keine gute Möglichkeit haben, die Linie abzugleichen, ist dies nicht allzu hilfreich.

Sie könnten etwas hacken, nehme ich an. Ich habe gerade keine Zeit, Code zu schreiben, aber ... etwas in diese Richtung. Ausführen git blame -n -L $n,$n $file. Das erste Feld ist das zuvor berührte Commit, und das zweite Feld ist die Zeilennummer in diesem Commit, da es sich hätte ändern können. Nehmen Sie diese und führen Sie sie aus git blame -n $n,$n $commit^ $file, dh ausgehend vom Commit vor dem letzten Ändern der Datei.

(Beachten Sie, dass dies fehlschlägt, wenn das letzte Commit, das die Zeile geändert hat, ein Zusammenführungs-Commit war. Dies kann in erster Linie passieren, wenn die Zeile im Rahmen einer Lösung für Zusammenführungskonflikte geändert wurde.)

Bearbeiten: Ich bin heute im März 2011 auf diesen Mailinglisten-Beitrag gestoßen, in dem dies erwähnt wird tigund der git guiüber eine Funktion verfügt, die Ihnen dabei hilft. Es sieht so aus, als ob die Funktion für Git selbst in Betracht gezogen, aber noch nicht fertiggestellt wurde.

Cascabel
quelle
6

Dies ruft git blamefür jede sinnvolle Überarbeitung zu zeigen Zeile $LINEder Datei $FILE:

git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE

Wie üblich zeigt die Schuld die Revisionsnummer am Anfang jeder Zeile. Sie können anhängen

| sort | uniq -c

Um aggregierte Ergebnisse zu erhalten, so etwas wie eine Liste von Commits, die diese Zeile geändert haben. (Nicht ganz, wenn Code nur verschoben wurde, wird möglicherweise dieselbe Commit-ID zweimal für verschiedene Inhalte der Zeile angezeigt. Für eine detailliertere Analyse müssten Sie einen verzögerten Vergleich der git blameErgebnisse für benachbarte Commits durchführen. )

krlmlr
quelle
Wieder denke ich, dass dies nicht funktioniert, weil es den vorherigen Ort dieser Zeile nicht verfolgt. Wenn also vor 2 Commits eine Zeile hinzugefügt wurde, würden Sie sich eine andere Zeile
ansehen
6

Hier ist eine Lösung, die einen Git-Alias ​​definiert, damit Sie ihn folgendermaßen verwenden können:

git rblame -M -n -L '/REGEX/,+1' FILE

Ausgabebeispiel:

00000000 18 (Not Committed Yet 2013-08-19 13:04:52 +0000 728) fooREGEXbar
15227b97 18 (User1 2013-07-11 18:51:26 +0000 728) fooREGEX
1748695d 23 (User2 2013-03-19 21:09:09 +0000 741) REGEXbar

Sie können den Alias ​​in Ihrer .gitconfig definieren oder einfach den folgenden Befehl ausführen

git config alias.rblame !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); echo $line; done' dumb_param

Dies ist ein hässlicher Einzeiler, daher hier eine nicht verschleierte äquivalente Bash-Funktion:

git-rblame () {
    local commit line
    while line=$(git blame "$@" $commit 2>/dev/null); do
        commit="${line:0:8}^"
        if [ "00000000^" == "$commit" ]; then
            commit=$(git rev-parse HEAD)
        fi
        echo $line
    done
}

Die Spitzhackelösung ( Git Log - Pickaxe-Regex -S'REGEX ' ) gibt Ihnen nur , nicht die anderen Änderungen der Zeile, die den regulären Ausdruck enthält.

Eine Einschränkung dieser Lösung ist die Schuld tad nur die 1. REGEX-Übereinstimmung zurückgibt. Wenn also mehrere Übereinstimmungen vorhanden sind, kann die Rekursion "springen", um einer anderen Zeile zu folgen. Überprüfen Sie unbedingt die vollständige Verlaufsausgabe, um diese "Sprünge" zu erkennen, und korrigieren Sie dann Ihren REGEX, um die Parasitenlinien zu ignorieren.

Schließlich ist hier eine alternative Version, die git show bei jedem Commit ausführt, um den vollen Unterschied zu erhalten:

git config alias.rblameshow !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); git show $commit; done' dumb_param
Lucas Cimon
quelle
2

Sie können git blameund git logBefehle mischen , um die Zusammenfassung jedes Commits im Befehl git tad abzurufen und anzuhängen. So etwas wie das folgende Bash + Awk-Skript. Die Commit-Zusammenfassung wird als Codekommentar inline angehängt.

git blame FILE_NAME | awk -F" " \
'{
   commit = substr($0, 0, 8);
   if (!a[commit]) {
     query = "git log --oneline -n 1 " commit " --";
     (query | getline a[commit]);
   }
   print $0 "  // " substr(a[commit], 9);
 }'

In einer Zeile:

git blame FILE_NAME | awk -F" " '{ commit = substr($0, 0, 8); if (!a[commit]) { query = "git log --oneline -n 1 " commit " --"; (query | getline a[commit]); } print $0 "  // " substr(a[commit], 9); }'
cserpell
quelle
2

In meinem Fall hatte sich die Zeilennummer im Laufe der Zeit stark geändert. Ich war auch auf Git 1.8.3, das Regex in "Git Blame -L" nicht unterstützt. (RHEL7 hat noch 1.8.3)

myfile=haproxy.cfg
git rev-list HEAD -- $myfile | while read i
do
    git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"
done | grep "<sometext>"

Einzeiler:

myfile=<myfile> ; git rev-list HEAD -- $myfile | while read i; do     git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"; done | grep "<sometext>"

Dies kann natürlich in ein Skript oder eine Funktion umgewandelt werden.

sastorsl
quelle