git diff umbenannte Datei

105

Ich habe eine Datei a.txt.

cat a.txt
> hello

Der Inhalt von a.txtist "Hallo".

Ich mache eine Verpflichtung.

git add a.txt
git commit -m "first commit"

Ich gehe dann a.txtin ein testVerzeichnis.

mkdir test
mv a.txt test

Ich mache dann mein zweites Commit.

git add -A
git commit -m "second commit"

Schließlich bearbeite ich, a.txtum stattdessen "Auf Wiedersehen" zu sagen.

cat a.txt
> goodbye

Ich mache mein letztes Commit.

git add a.txt
git commit -m "final commit"

Hier ist meine Frage:

Wie unterscheide ich den Inhalt a.txtzwischen meinem letzten und meinem ersten Commit?

Ich habe versucht:, git diff HEAD^^..HEAD -M a.txtaber das hat nicht funktioniert. git log --follow a.txterkennt die Umbenennung richtig, aber ich kann kein Äquivalent für finden git diff. Ist dort eines?

Ken Hirakawa
quelle
Ich nehme an, es wäre dasselbe, wenn Sie einen 'git mv a.txt-Test' machen würden? IE Sie haben die Datei nur umbenannt, anstatt sie in ein Unterverzeichnis zu verschieben.
Max Waterman

Antworten:

107

Das Problem mit dem Unterschied zwischen HEAD^^und HEADist, dass Sie a.txtin beiden Commits eine haben. Wenn Sie also nur diese beiden Commits berücksichtigen (was diff tut), gibt es keine Umbenennung, es gibt eine Kopie und eine Änderung.

Um Kopien zu erkennen, können Sie Folgendes verwenden -C:

git diff -C HEAD^^ HEAD

Ergebnis:

index ce01362..dd7e1c6 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1 @@
-hello
+goodbye
diff --git a/a.txt b/test/a.txt
similarity index 100%
copy from a.txt
copy to test/a.txt

Übrigens, wenn Sie Ihr Diff auf nur einen Pfad beschränken (wie in) werden git diff HEAD^^ HEAD a.txtSie die Umbenennungen oder Kopien nie sehen, da Sie alles außer einem einzelnen Pfad ausgeschlossen haben und Umbenennungen oder Kopien - per Definition - zwei umfassen Wege.

CB Bailey
quelle
2
Nehmen wir an, das Commit enthielt mehrere Dateiänderungen. Wie würde ich es auf einen Unterschied einer einzelnen Datei eingrenzen?
Ken Hirakawa
3
@ KenHirakawa verwenden -- <old-path> <new-path>... siehe meine Antwort.
Nolan Amy
In meinem Fall wollte ich die Details eines Commits anzeigen, bei dem die Datei umbenannt wurde, aber es zeigte mir nur, dass eine Datei gelöscht und eine Datei hinzugefügt wurde ... Ich lief git show -C [commit]und es erkannte die Umbenennung der Datei und zeigte mir die Unterschied zwischen den Dateien. Perfekt.
Jason
83

Verwenden Sie -M -- <old-path> <new-path>( -Cfunktioniert auch) , um über eine Umbenennung einer bestimmten Datei zu unterscheiden .

Wenn Sie also beim letzten Festschreiben eine Datei umbenannt und geändert haben, können Sie die Änderungen wie folgt anzeigen:

git diff HEAD^ HEAD -M -- a.txt test/a.txt

Dies erzeugt:

diff --git a/a.txt b/test/a.txt
similarity index 55%
rename from a.txt
rename to test/a.txt
index 3f855b5..949dd15 100644
--- a/a.txt
+++ b/test/a.txt
@@ -1,3 +1,3 @@
 // a.txt

-hello
+goodbye

( // a.txtZeilen hinzugefügt, um Git beim Erkennen der Umbenennung zu helfen)


Wenn git die Umbenennung nicht erkennt, können Sie einen niedrigen Ähnlichkeitsschwellenwert mit beispielsweise -M[=n]1% angeben :

git diff HEAD^ HEAD -M01 -- a.txt test/a.txt

Aus den Git Diff-Dokumenten :

-M [<n>] --find-renames [= <n>]

Umbenennungen erkennen. Wenn nangegeben, handelt es sich um einen Schwellenwert für den Ähnlichkeitsindex (dh die Anzahl der Hinzufügungen / Löschungen im Vergleich zur Dateigröße). -M90%Dies bedeutet beispielsweise, dass Git ein Lösch- / Hinzufügen-Paar als Umbenennung betrachten sollte, wenn sich mehr als 90% der Datei nicht geändert haben. Ohne %Vorzeichen ist die Zahl als Bruch mit einem Dezimalpunkt vorzulesen. Dh -M5wird 0,5 und ist somit das gleiche wie -M50%. Ebenso -M05ist das gleiche wie -M5%. Verwenden Sie, um die Erkennung auf genaue Umbenennungen zu beschränken -M100%. Der Standard-Ähnlichkeitsindex beträgt 50%.

Nolan Amy
quelle
... Funktioniert natürlich auch, wenn die Änderung und Umbenennung in separaten Commits erfolgen, wie im ursprünglichen Beispiel:git diff HEAD^^ HEAD -M -- a.txt test/a.txt
Nolan Amy
1
Nur wenn der Inhalt der Dateien nah genug ist, dass diff einen Ähnlichkeitsindex erstellt. Wenn Sie beide Optionen (-M und -C) verwenden, wird der Unterschied zu / dev / null und von / dev / null in einer Datei angezeigt, die umbenannt wurde und sich vollständig geändert hat (einschließlich Einrückungen). Beim Ignorieren wird er nicht einmal abgefangen Leerzeichen.
DavidG
37

Sie können auch tun:

git diff rev1:file1 rev2:file2

was für Ihr Beispiel wäre

git diff HEAD^^:./a.txt HEAD:./test/a.txt

Beachten Sie die explizite ./ - dieses Format setzt ansonsten voraus, dass die Pfade relativ zur Wurzel des Repos sind. (Wenn Sie in der Wurzel des Repos sind, können Sie das natürlich weglassen.)

Dies hängt überhaupt nicht von der Umbenennungserkennung ab, da der Benutzer explizit genau angibt, was zu vergleichen ist. (Daher ist es auch unter anderen Umständen nützlich, z. B. beim Vergleichen von Dateien zwischen verschiedenen SVN-Zweigen in einer Git-SVN-Umgebung.)

benkc
quelle
1
Oooh, das ist schön!
Nolan Amy
Für eine Umbenennung mit zusätzlichen Dateiänderungen, die über eine Zusammenführung vorgenommen wurden, ist dies die einzige Antwort, die für mich funktioniert hat. Vielen Dank!
Lane Rettig
1

Wenn Ihr Umbenennungs-Commit bereitgestellt, aber noch nicht festgeschrieben ist, können Sie Folgendes verwenden:

git diff --cached -M -- file.txt renamed_file.txt
Mr-IDE
quelle