Wie kann man mit git WIRKLICH Protokolle umbenannter Dateien anzeigen?

132

Ich bin relativ neu in Git, ich habe Subversion schon einmal benutzt.

Mir ist aufgefallen, dass die meisten grafischen Git-Frontends und IDE-Plugins den Verlauf einer Datei nicht anzeigen können, wenn die Datei umbenannt wurde. Wenn ich benutze

git log --follow

In der Befehlszeile kann ich das gesamte Protokoll über Umbenennungen hinweg sehen.

Laut Linus Torvalds ist der --follow-Schalter ein "SVN noob" -Lustiger, ernsthafte Git-Benutzer verwenden ihn nicht:

--follow ist ein totaler Hack, der nur Ex-SVN-Benutzer zufriedenstellen soll, die sowieso nie etwas über Dinge wie Elternschaft oder nette Revisionsgraphen gewusst haben.

Es ist nicht ganz grundlegend, aber die aktuelle Implementierung von "--follow" ist wirklich eine schnelle Vorverarbeitung, die mit der Revisionslauflogik verknüpft ist, anstatt etwas wirklich Integrales zu sein.

Es wurde buchstäblich als "SVN Noob" -Lustiger entworfen, nicht als "echte Git-Funktionalität". Die Idee war, dass Sie sich von der (gebrochenen) Denkweise lösen würden, die Materie im großen Ganzen umbenennt.

Meine Frage : Wie erhalten die Hardcore-Git-Benutzer unter Ihnen den Verlauf einer Datei, als sie umbenannt wurde? Was ist der "echte" Weg, dies zu tun?

Mike
quelle
17
@ David Hall: git mv oldfile newfileverursacht keine der Umbenennungs aufgezeichnet werden überhaupt - es ist genau das gleiche wie eine Datei zu löschen und eine andere hinzufügen. git arbeitet nur bei jedem Commit nachträglich Umbenennungen und Kopien aus dem Status des Baums aus.
Mark Longair
20
@ David Hall: Wenn Sie die Datei mit einem anderen Tool außerhalb von git (z. B. /bin/mv oldfile newfile) umbenennen , dies aber tun git add newfile; git rm oldfile, ist das Ergebnis nicht von dem von zu unterscheiden git mv oldfile newfile.
Mark Longair
1
Diese Ideologie fällt auseinander, wenn Sie jemals eine Datei in ein neues Repository verschieben. In diesem Fall kann die Unfähigkeit, den gesamten Verlauf zu verschieben, ein großes Problem sein. Obwohl es natürlich Grenzen gibt, wie viel wahre Geschichte mit einer Datei in einem komplexen Projekt wirklich kommen kann.
Roman Starkov
1
Hinweis: git log --followverbessert sich ein bisschen mit Git 2.9 (Juni 2016): siehe meine Antwort unten
VonC
1
Ab Version 2.15 möchten Sie möglicherweise experimentieren, --color-movedwenn Sie diff.
Michael - Wo ist Clay Shirky

Antworten:

71

Ich denke, dass der allgemeine Antrieb hinter Linus Point darin besteht, dass Hardcore-Git-Benutzer sich - und das mit einer Prise Salz - niemals um den Verlauf einer "Datei" kümmern. Sie legen Inhalte in einem Git-Repository ab, da der gesamte Inhalt einen aussagekräftigen Verlauf hat.

Ein Umbenennen von Dateien ist ein kleiner Sonderfall, bei dem sich "Inhalt" zwischen Pfaden bewegt. Möglicherweise haben Sie eine Funktion, die zwischen Dateien wechselt, die ein Git-Benutzer möglicherweise funktional mit "Spitzhacke" aufspürt (z log -S. B. ).

Andere "Pfad" -Änderungen umfassen das Kombinieren und Teilen von Dateien; git ist es egal, welche Datei Sie als umbenannt betrachten und welche Sie als kopiert (oder umbenannt und gelöscht) betrachten. Es verfolgt lediglich den gesamten Inhalt Ihres Baums.

git regt zum "Ganzbaum" -Denken an, bei dem ebenso viele Versionskontrollsysteme sehr dateizentriert sind. Aus diesem Grund bezieht sich git häufiger auf "Pfade" als auf "Dateinamen".

CB Bailey
quelle
Hallo Charles, danke für deine Antwort. Es scheint, dass ich git genauso benutze wie SVN. Obwohl ich verstehe, dass Git sich sehr von anderen Versionskontrollsystemen unterscheidet, erscheinen mir viele Konzepte in Git noch seltsam ... Ich sollte wahrscheinlich das Git-Buch fertigstellen, das ich kürzlich gekauft habe.
Mike
24
Linus 'Argument war, dass eine "richtige" GUI in der Lage sein würde, Codestücke über Dateien hinweg zu verfolgen, und er hoffte, dass wir jetzt solche Tools haben würden. Leider haben wir diesen Luxus immer noch nicht und --follow ist immer noch nützlich.
Michael Parker
11
Gibt Ihnen Git tatsächlich eine andere Lösung als --followdiese?
Griwes
13
Ich würde argumentieren, dass das Denken "ganzer Baum" durch --followdie Standardeinstellung verbessert wird . Was ich meine ist, wenn ich den Verlauf des Codes in einer Datei sehen möchte, ist es mir normalerweise egal, ob die Datei umbenannt wurde oder nicht, ich möchte nur den Verlauf des Codes sehen, unabhängig von der Umbenennung. Meiner Meinung nach ist es daher sinnvoll --follow, die Standardeinstellung zu verwenden, da mir einzelne Dateien egal sind. --followhilft mir, einzelne Umbenennungen von Dateien zu ignorieren, die normalerweise ziemlich belanglos sind.
Eddified
2
Also ... wenn ich mich für den "Inhalt" anstelle der Datei entscheide, wie drucke ich die Commits, die für den Inhalt relevant sind, der sich derzeit in dieser Datei befindet? Ich würde mich freuen, wenn git alles für mich in verschiedenen Dateien nachverfolgen und ein Protokoll aller Änderungen melden würde - ich sehe nur nicht, wie ich es bekommen soll.
Ed Avis
36

Ich habe genau das gleiche Problem, mit dem Sie konfrontiert sind. Obwohl ich Ihnen keine Antwort geben kann, glaube ich, dass Sie diese E-Mail lesen können, die Linus 2005 geschrieben hat. Sie ist sehr relevant und gibt Ihnen möglicherweise einen Hinweis, wie Sie mit dem Problem umgehen können:

… Ich behaupte, dass jeder SCM, der versucht, Umbenennungen zu verfolgen, grundsätzlich fehlerhaft ist, es sei denn, dies geschieht aus internen Gründen (dh um effiziente Deltas zu ermöglichen), genau weil Umbenennungen keine Rolle spielen. Sie helfen dir nicht und sie sind sowieso nicht das, woran du interessiert warst .

Was zählt, ist herauszufinden, "woher das kommt", und die Git-Architektur macht das in der Tat sehr gut - viel besser als alles andere da draußen. …

Ich fand es in diesem Blog-Beitrag referenziert , was auch für Sie nützlich sein könnte, um eine praktikable Lösung zu finden:

In der Nachricht skizzierte Linus, wie Sie mit einem idealen Content-Tracking-System herausfinden können, wie ein Codeblock in die aktuelle Form gekommen ist. Sie beginnen mit dem aktuellen Codeblock in einer Datei und gehen in den Verlauf zurück, um das Commit zu finden, mit dem die Datei geändert wurde. Anschließend überprüfen Sie die Änderung des Commits, um festzustellen, ob der Codeblock, an dem Sie interessiert sind, von diesem geändert wird, da ein Commit, das die Datei ändert, möglicherweise nicht den Codeblock berührt, an dem Sie interessiert sind, sondern nur einige andere Teile des Commits Datei.

Wenn Sie feststellen, dass der Codeblock vor dem Festschreiben nicht in der Datei vorhanden war, überprüfen Sie das Festschreiben eingehender. Sie können feststellen, dass dies eine der vielen möglichen Situationen ist, einschließlich:

  1. Das Commit hat den Codeblock wirklich eingeführt. Der Autor des Commits war der Erfinder des coolen Features, nach dem Sie gesucht haben (oder der Schuldige, der den Fehler eingeführt hat). oder
  2. Der Codeblock war in der Datei nicht vorhanden, aber fünf identische Kopien davon waren in verschiedenen Dateien vorhanden, die alle nach dem Festschreiben verschwunden sind. Der Autor des Commits hat den duplizierten Code überarbeitet, indem er eine einzelne Hilfsfunktion eingeführt hat. oder
  3. (als Sonderfall) Vor dem Festschreiben war die Datei, die derzeit den Block des Codes enthält, an dem Sie interessiert sind, nicht vorhanden, aber eine andere Datei mit nahezu identischem Inhalt war vorhanden, und der Block des Codes, an dem Sie interessiert sind. zusammen mit allen anderen Inhalten in der Datei existierte damals, existierte in dieser anderen Datei. Es ging nach dem Commit weg. Der Autor des Commits hat die Datei umbenannt und geringfügig geändert.

In Git gibt es das ultimative Content-Tracking-Tool von Linus noch nicht vollständig automatisiert. Die meisten wichtigen Zutaten sind jedoch bereits verfügbar.

Bitte halten Sie uns über Ihre Fortschritte auf dem Laufenden.

Alberto Bacchelli
quelle
Vielen Dank für die Veröffentlichung dieser Artikel. Erst als ich sie gelesen habe, habe ich die Idee der Inhaltsgeschichte vollständig verstanden! Ich habe falsch darüber nachgedacht!
DavidG
Diese E-Mail von Linus ist großartig, danke, dass du sie gepostet hast.
mik01aj
Unterhaltsame--color-moved Tatsache, Git v2.15 fügt einen Schritt in Richtung dieses "idealen Tracking-Systems" hinzu. Ich habe damit gespielt, um zu sehen, wie es verschobene Linien in einer Datei verfolgt, aber versehentlich festgestellt, dass es verschobene Linien im gesamten Diff verfolgt.
Michael - Wo ist Clay Shirky
2
Linus erklärt eine komplexe Situation. Aber hier haben wir eine einfache Situation: Eine Datei wurde gerade umbenannt (oder in ein anderes Verzeichnis verschoben). Daher sollte es eine einfache Lösung geben. Ich denke, dass das Problem von der Tatsache herrührt, dass der Benutzer Git im Gegensatz zu Subversion nicht zum Festschreibungszeitpunkt anweisen kann, woher eine Datei stammt, und das --followkann falsch sein (z. B. wenn 2 Dateien den gleichen Inhalt haben oder wenn es eine Änderung gibt zusätzlich zum Dateiwechsel).
vinc17
13

Ich habe festgestellt, dass die meisten grafischen Git-Frontends und IDE-Plugins den Verlauf einer Datei nicht anzeigen können, wenn die Datei umbenannt wurde

Sie werden froh sein zu wissen, dass einige beliebte Git-UI-Tools dies jetzt unterstützen. Es gibt Dutzende von Git-UI-Tools, daher werde ich nicht alle auflisten, aber zum Beispiel:

  • Wenn SourceTree ein Dateiprotokoll anzeigt, ist unten links das Kontrollkästchen "Umbenannte Dateien folgen" aktiviert
  • TortoiseGit hat unten links im Protokollfenster das Kontrollkästchen "Umbenennen folgen".

Weitere Informationen zu Git UI-Tools:

Michael Parker
quelle
Die Quelle eignet sich hervorragend, wenn Sie sie einmal umbenennen. Wenn Sie sie zweimal umbenennen, sind Änderungsdetails für Commits vor dem Umbenennen nicht verfügbar. Ich habe den Fehler hier gemeldet: jira.atlassian.com/browse/SRCTREE-5715
Intel
gitk funktioniert auch dann hervorragend, wenn eine Datei im Verlauf zweimal umbenannt wird. Der Befehl sieht so aus: "gitk --follow path / to / file"
Intel
6

Hinweis: Git 2.9 (Juni 2016) wird die "Buggy" -Natur von git log --follow:

Siehe Commit ca4e3ca (30. März 2016) von SZEDER Gábor ( szeder) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 26effb8 , 13. April 2016)

diffcore: Korrigiert die Iterationsreihenfolge identischer Dateien während der Umbenennungserkennung

Wenn die beiden Pfade ' dir/A/file' und ' dir/B/file' identischen Inhalt haben und das übergeordnete Verzeichnis umbenannt wird, z. B. ' git mv dir other-dir', werden diffcoredie folgenden genauen Umbenennungen gemeldet:

renamed:    dir/B/file -> other-dir/A/file
renamed:    dir/A/file -> other-dir/B/file

(Beachten Sie die Umkehrung hier : B/file -> A/file, und A/file -> B/file)

Obwohl dies technisch nicht falsch ist, ist dies nicht nur für den Benutzer verwirrend, sondern auch für Git-Befehle, die Entscheidungen auf der Grundlage von Umbenennungsinformationen treffen, z. B. git log --follow other-dir/A/file"folgt dir/B/file" nach dem Umbenennen.

Dieses Verhalten ist ein Nebeneffekt von Commit v2.0.0-rc4 ~ 8 ^ 2 ~ 14 ( diffcore-rename.c: Vereinfachen Sie das Auffinden genauer Umbenennungen, 14.11.2013): Die Hashmap, die Quellen speichert, gibt Einträge aus demselben Bucket zurück, dh Quellen, die mit dem aktuellen Ziel übereinstimmen in LIFO-Reihenfolge.
Daher untersucht die Iteration zuerst ' other-dir/A/file' und ' dir/B/file' und meldet, wenn identischer Inhalt und Basisname gefunden werden, eine genaue Umbenennung.

VonC
quelle
2

Unter Linux habe ich überprüft, ob SmartGit und GitEye Umbenennungen folgen können, wenn sie dem Verlauf einer bestimmten Datei folgen. Im Gegensatz zu gitk und GitEye zeigt SmartGit jedoch eine separate Datei- und Repository-Ansicht an (die die Verzeichnisstruktur, jedoch nicht die Liste der darin enthaltenen Dateien enthält).

prusswan
quelle