Wie finde ich das letzte Git-Commit, das eine Datei geändert hat?

177

Ich möchte das letzte Commit finden, das eine Quelldatei geändert hat.

Ich kann git blamealle Daten für Commits in jeder Zeile anzeigen, aber es ist schwierig, genau zu erkennen, welches Commit das letzte war, das die Datei berührt hat.

Wie kann ich das letzte Commit finden, das eine bestimmte Datei in meinem Git-Repository berührt hat?

Cory Klein
quelle

Antworten:

226

git log unterstützt das Anzeigen des Verlaufs bestimmter Dateien (und Verzeichnisse), sodass Sie ihn folgendermaßen aufrufen können:

git log my/file.c

Wenn Sie wirklich nur die auflisten wollen eine letzte begehen, zum Beispiel in einem Skript zu verwenden, verwenden Sie die -n 1Option:

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%hweist git logan, nur den Commit-Hash anzuzeigen. Das --Trennzeichen verhindert, dass der Dateiname als Festschreibungsname interpretiert wird, falls er nicht eindeutig ist.

Jo Liss
quelle
12
Wenn Sie wissen möchten, wann eine Datei das letzte Mal geändert wurde, können Sie alle Zweige berücksichtigen, indem Sie die --allOption hinzufügen .
KC
44

Wenn Sie nur das aktuellste Commit suchen möchten git-log, möchten Sie nicht git-rev-list, sondern die Commit-Objekte, die diese Datei ändern, in diesem Commit-Pfad auflisten, beginnend mit dem neuesten (chronologisch). Einfach gesagt:

git rev-list -1 <commit> <filename>

Denn git-rev-listin Ihrem Fall liefern Sie nur:

  • Die Anzahl der einzuschließenden Commits oder -1 nur für die aktuellsten.
  • Der Zweig (oder die Festschreibungs-ID), von dem aus Sie zurückblicken möchten , HEAD, wenn Sie bereits darauf sind, oder --all, wenn Sie alle bekannten Festschreibungen wünschen, und
  • Der relative Pfad zu Ihrer Datei.

Dies gibt nur die letzte Festschreibungs-ID im aktuellen Zweig zurück, um diese Datei zu ändern, z. 215095e2e338525be0baeeebdf66bfbb304e7270

Für ein komplexeres Beispiel können Sie Tag-Namen und sogar Remote-Referenzen verwenden und relative Pfadnamen mit Platzhaltern einschließen, z.

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

... Was Ihnen sagen würde, was die letzte Änderung am Wildcard-Match in der Geschichte dieses Zweigs war. Die Optionen für die Rev-Liste sind extrem. Dies ist einer der wichtigsten Installationsbefehle, sodass Sie nach nahezu allen erdenklichen Kriterien ein- oder ausschließen können.

Natürlich beziehen sich auf die git-rev-Liste (1) Handbuch Seite .

Michael Erickson
quelle
Sie haben wirklich nicht erklärt, warum die Verwendung git-logminderwertig ist.
Piotr Dobrogost
7
Ich würde nicht minderwertig sagen, nur dass es standardmäßig irrelevante Informationen liefert. git-rev-list gibt nur die Festschreibungs-ID zurück, die Sie möchten, wenn Sie die Antwort in ein Skript oder einen anderen Automatisierungsprozess einspeisen möchten. git-log gibt Informationen zu den ausgewählten Commits zurück, indem zuerst die Commit-IDs mithilfe von git-rev-list und dann Informationen zu jedem Commit erfasst werden. Wenn Sie nur die Commit-Informationen herausfiltern und die IDs verwenden möchten, können Sie zunächst nur git-rev-list verwenden. Da das Protokoll auf der Rev-Liste basiert, werden die meisten Filterparameter verwendet.
Michael Erickson
3
git-logist Porzellan, git-rev-listist Sanitär.
blitzen9872
27

Wenn Sie nur den Hash des neuesten Commits abrufen möchten, um einen bestimmten Satz von Dateien zu ändern (und dies vermeiden möchten awk), können Sie Folgendes verwenden:

git log -n 1 --pretty=format:%h -- <path>

Dies kann nützlich sein, um den Commit-Hash für die spätere Verwendung mit zu erhalten git describe.

Zum Beispiel (falls es für jemanden nützlich ist)…

Ich erstelle eine aktuelle Versions-ID, indem ich das letzte Commit zum Ändern einer Quelldatei berücksichtige (vorausgesetzt, Sie markieren Versionen mit Tags wie mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

Dies erzeugt IDs wie:

  • mycode-1.2.1 - wenn der aktuelle Status der Quelldateien einer getaggten Version entspricht
  • mycode-1.2.1-g3k7s2 - wenn der aktuelle Status der Quelldateien dem Festschreiben nach einer getaggten Version entspricht
  • mycode-1.2.1-g3k7s2-mod - wenn der aktuelle Status der Quelldateien seit dem letzten Commit nach einer getaggten Version geändert wurde
  • mycode-unknown - wenn noch kein Versions-Tag erstellt wurde
TheBamf
quelle
5
$VNsieht aus wie eine Art Albtraum untoter SVN
ThorSummoner
10

Ich bin nicht sicher, ob dies das ist, was Sie wollen, aber ob Sie a tun git log <thefile>, um die Commits zu erhalten, die diese Datei geändert haben. Sie können die oberste auswählen. Es sollte derjenige sein, den Sie suchen.

Noufal Ibrahim
quelle
4
Wenn Sie git log -n1 -- <thefile>die Ausgabe verwenden (oder weiterleiten, head -1wenn Sie Ressourcen verschwenden möchten), müssen Sie die oberste Zeile nicht manuell auswählen (siehe Jo Liss ' Antwort )
Tobias Kienzler
4
Guter Punkt. Ich denke, Sie können das auch überspringen -nund -1direkt verwenden.
Noufal Ibrahim
3

Versuchen Sie Folgendes, um nur den Schiedsrichter in einer Zeile zu erhalten:

git log -n1 --oneline <path> | awk '{print $1;}'
schnelle Vervielfachung
quelle
2

Sobald Sie die SHA-ID des Commits haben, das Sie verwenden möchten git log FILENAME, sollten Sie in der Lage sein, git show SHA_ID_HEREzu sehen, was Sie für dieses bestimmte Commit getan haben. Sie müssen nicht einmal die gesamte ID eingeben. Die ersten 6 Zeichen sollten ausreichen.

Joe
quelle
4
Das ist etwas mehr als vom OP verlangt, aber git show $(git log -1 --pretty="%H" -- FILENAME)
Tobias Kienzler