Nehmen Sie den Dateikopiervorgang mit Git auf


141

Wenn ich eine Datei in git mit git-mv verschiebe, zeigt der Status an, dass die Datei umbenannt wurde, und selbst wenn ich einige Teile ändere, wird sie immer noch als fast dasselbe angesehen (was gut ist, weil ich damit den Verlauf verfolgen kann). .

Wenn ich eine Datei kopiere, hat die Originaldatei einen Verlauf, den ich der neuen Kopie zuordnen möchte.

Ich habe versucht, die Datei zu verschieben und dann erneut am ursprünglichen Speicherort auszuchecken. Sobald git verschoben wurde, kann ich den ursprünglichen Speicherort nicht mehr auschecken.

Ich habe versucht, eine Dateisystemkopie zu erstellen und dann die Datei hinzuzufügen - git listet sie als neue Datei auf.

Gibt es eine Möglichkeit, Git Record zu einem Dateikopiervorgang zu machen, ähnlich wie es ein Umbenennen / Verschieben von Dateien aufzeichnet, bei dem der Verlauf auf die Originaldatei zurückgeführt werden kann?

Antworten:


112

Git ist nicht Umbenennungs Tracking noch Kopie Tracking, das heißt es nicht Datensatz Umbenennungen oder Kopien. Stattdessen wird die Erkennung umbenannt und kopiert . Sie können die Umbenennungserkennung in git diff(und git show) mithilfe der -MOption anfordern, Sie können mithilfe der -COption ( -Cimpliziert -M) eine zusätzliche Kopiererkennung in geänderten Dateien anfordern und Sie können eine teurere Kopiererkennung für alle Dateien mit --find-copies-harderoder -C -C(was impliziert -C, was impliziert ) anfordern -M). Siehe die git-diff- Manpage.

Sie können git auch so konfigurieren, dass die Erkennung immer umbenannt wird, indem Sie diff.renameseinen booleschen wahren Wert (z. B. trueoder 1) festlegen, und Sie können git anfordern, auch die Kopiererkennung durchzuführen, indem Sie ihn auf copyoder setzen copies. Siehe die git-config- Manpage.

Überprüfen Sie auch die -lOption git diffund die zugehörige Konfigurationsvariable diff.renameLimit.


Beachten Sie, dass git log <pathspec>dies in Git anders funktioniert: Hier finden Sie <pathspec>eine Reihe von Pfadbegrenzern, wobei path ein (Unter-) Verzeichnisname sein kann. Es filtert und vereinfacht den Verlauf, bevor die Umbenennung und Kopiererkennung ins Spiel kommt. Wenn Sie Umbenennungen und Kopien folgen möchten, verwenden Sie git log --follow <filename>(was derzeit etwas eingeschränkt ist und nur für einzelne Dateien funktioniert).


1
@allyourcode: Worüber bist du verwirrt? Um die Kopiererkennung standardmäßig diff.renameszu aktivieren, stellen Sie copies(z git config diff.renames copies. B. ' ') ein. Ich bin damit einverstanden, dass es ein bisschen eingängig ist.
Jakub Narębski

Ein Abschnitt, den ich scheinbar nicht analysieren kann, ist "und Sie können anfordern, standardmäßig auch die Erkennung umzubenennen". Wollen Sie damit sagen, dass diff.renames vier Werte verwenden kann (true, 1, copy, copy) und dass alle dasselbe tun?
Allyourcode

1
@allyourcode: Es tut mir leid, ich habe das nicht bemerkt. Jetzt behoben, danke.
Jakub Narębski

4
@ peschü: Git verwendet eine inhaltsadressierte Objektdatenbank als Repository-Speicher. Der Dateiinhalt wird im 'Blob'-Inhalt unter der Adresse gespeichert, die SHA-1-Hash des Inhalts ist (also Typ + Länge + Inhalt). Dies bedeutet, dass bestimmte Inhalte nur einmal gespeichert werden. Nb. Diese automatische Deduplizierung war der Grund für die Erstellung eines "Bup" -Sicherungssystems im Git-Pack-Format.
Jakub Narębski

1
Im Gegensatz zur folgenden Lösung funktioniert dies nicht mit der Änderungsverfolgung in einem Bereich. Das Git-Protokoll erlaubt ein Bereichsargument ( git log -L123,456:file.xyz), das Umbenennungen ordnungsgemäß folgt, jedoch keine Kopien, und Sie können --follow in diesem Fall nicht übergeben. AFAICT funktioniert auch nicht mit Git-Schuld.
Clément

57

2020-05-19: Die folgende Lösung bietet den Vorteil, dass das Protokoll der Originaldatei nicht geändert, kein Zusammenführungskonflikt erstellt und kürzer wird.

Sie können Git zwingen, den Verlauf der kopierten Datei in drei Commits zu erkennen:

  • Wechseln Sie statt zu kopieren zu einem neuen Zweig und verschieben Sie ihn die Datei an ihren neuen Speicherort.
  • Fügen Sie dort die Originaldatei erneut hinzu.
  • Führen Sie den neuen Zweig mit der Option "Kein schneller Vorlauf" mit dem ursprünglichen Zweig zusammen --no-ff.

(Credits gehen an Raymond Chen .)


Die frühere Lösung hatte vier Commits:

  • Wechseln Sie statt zu kopieren zu einem neuen Zweig und verschieben Sie die Datei an ihren neuen Speicherort.
  • Wechseln Sie zum ursprünglichen Zweig und benennen Sie die Datei um.
  • Führen Sie den neuen Zweig in den ursprünglichen Zweig ein und lösen Sie den trivialen Konflikt, indem Sie beide Dateien behalten.
  • Stellen Sie den ursprünglichen Dateinamen in einem separaten Commit wieder her.

(Lösung von https://stackoverflow.com/a/44036771/1389680 .)


7
Einfachheit, Kürze, 100% ... Diese Antwort ist ein öffentlicher Dienst ... alles in Sichtweite zu
verbessern

Was ist der Unterschied zwischen moveund rename?
Vovan

@vovan Beziehen Sie sich auf die Tatsache, dass Sie in Bash mvfür beide Operationen verwenden würden? Ich habe 'move' für den Fall verwendet, bei dem möglicherweise das Verzeichnis der Datei geändert wird, und 'umbenennen' für den Fall, dass dies nicht der Fall ist.
Robert Pollak

Ich habe versucht, diesem (neuen) Rezept zu folgen und es hat nicht funktioniert. Es kann hilfreich sein, wenn Sie die tatsächlichen Befehle anzeigen.
Greg Lindahl
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.