Kann ich eine git-kompatible Ausgabe von git-diff erhalten?

160

Ich mache etwas sehr einfaches falsch. Ich versuche, eine normale Patch-Datei vorzubereiten, damit ich einige Änderungen erneut anwenden kann:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

Mit something_here leer funktioniert es fast, aber die Dateinamen sind nicht richtig. Ich glaube, ich vermisse nur eine Option.

Im wirklichen Leben werde ich nach dem Auschecken eine Zusammenführung durchführen, sodass der Patch dort möglicherweise fehlschlägt, aber Sie sehen, worauf ich hinaus will.

Bearbeiten Sie meine Schuld hier, weil Sie die falsche Frage gestellt haben. Die eigentliche Frage lautet: Ich möchte meine Änderungen speichern, zusammenführen und die Änderungen nach Möglichkeit erneut anwenden. Ich habe es falsch gefragt, weil ich es gewohnt bin , Patches zur Lösung dieser Art von Problemen zu verwenden, und es git diffsah so aus, als wollte ich das tun.

Charles Baileys Kommentar hatte die richtige Antwort. Für mich ist Git-Apply das Richtige (Git-Stash sieht schwerer aus als ich brauche und Rebasing und Bundles liegen definitiv über meinem derzeitigen Kenntnisstand.) Ich werde die Antwort akzeptieren, die Charles gegeben hat (weil Sie kann keinen Kommentar annehmen). Vielen Dank für alle Vorschläge.

Bearbeiten, 6 Jahre später Wie jeder weiß, der mit dem Thema vertraut ist, habe ich die Schwierigkeit von überschätzt git stash. Fast jeden Tag oder so werde ich die folgende Sequenz verwenden:

$ git stash
$ git merge
$ git stash pop
Malvolio
quelle
8
Gibt es einen Grund, den Sie speziell verwenden möchten, patchanstatt git apply?
CB Bailey
3
Und selbst dann brauchen Sie wirklich Patches anstatt so etwas git stashoder andere Git-Tools?
CB Bailey
3
Nach der Bearbeitung ist dies meiner Meinung git stashnach die einfachste Lösung für das, was Sie versuchen, aber es gibt viele Ansätze, die funktionieren.
CB Bailey
1
@ Malvolio: In der Tat müssen Sie nicht einmal an einen temporären Dateinamen denken, um Ihren Patch zu speichern.
CB Bailey
4
@Charlse, manchmal musst du einen Patch an jemanden ohne das gesamte Git-Repository senden. Zum Beispiel bei Verwendung git-svn.
Elazar Leibovich

Antworten:

139

Wenn Sie Patch verwenden möchten, müssen Sie die a/ b/Präfixe entfernen, die git standardmäßig verwendet. Sie können dies mit der --no-prefixOption tun (Sie können dies auch mit der Option des Patches tun -p):

git diff --no-prefix [<other git-diff arguments>]

Normalerweise ist es jedoch einfacher, Straight zu verwenden git diffund dann den Ausgang zum Einspeisen zu verwenden git apply.

Die meiste Zeit versuche ich, die Verwendung von Textpatches zu vermeiden. In der Regel sind ein oder mehrere temporäre Commits in Kombination mit Rebase git stashund Bundles einfacher zu verwalten.

Für Ihren Anwendungsfall halte ich das stashfür am besten geeignet.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
quelle
7
git diff --no-prefix master > diff.patchund danngit checkout master patch -p0 < diff.patch
Natim
1
@ Natim Für ultimative Sicherheit würde ich empfehlen, patch --dry-run < diff.patchvor der Ausgabe des letzten Befehls zu verwenden.
20.
1
@ ᴠɪɴᴄᴇɴᴛ was wäre der Vorteil davon? Da wir Git verwenden, ist es unwahrscheinlich, dass wir etwas verlieren, nicht wahr?
Natim
1
@ Natim Wie gesagt, nur für ultimative Sicherheit, keine Notwendigkeit, im Fehlerfall etwas rückgängig zu machen. Ich habe auch über Leute nachgedacht, die dies lesen und patchaußerhalb von git (möglicherweise unter Verwendung einer von generierten Patch-Datei diff) in einem allgemeineren Anwendungsfall verwenden möchten .
26.
Um neue Dateien in Ihren Patch aufzunehmen, müssen Sie auch "git diff --no-prefix --cached" in den Patch aufnehmen. Vielleicht gibt es einen besseren Weg?
Jamshid
219

Einfach verwenden -p1: Sie müssen -p0in dem --no-prefixFall sowieso verwenden, so können Sie einfach das weglassen --no-prefixund verwenden -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
quelle
1
Wenn Sie sich fragen, warum, fasst der Mann es gut zusammen - Quelle .
TutuDajuju
3
Dies funktioniert nicht mit Umbenennungen. git diffgibt eine Zeile aus, die patchignoriert wird. git applyist der Weg zu gehen.
Hraban
17

Den Git-Diffs ist den Dateipfaden ein zusätzliches Pfadsegment vorangestellt. Sie können diesen Eintrag im Pfad entfernen, indem Sie -p1 mit Patch wie folgt angeben:

patch -p1 < save.patch
Henrik Gustafsson
quelle
10
  1. Ich speichere den Unterschied des aktuellen Verzeichnisses (einschließlich nicht festgeschriebener Dateien) gegen den aktuellen HEAD.
  2. Anschließend können Sie die save.patchDatei an einen beliebigen Ort transportieren (einschließlich Binärdateien).
  3. Wenden Sie den Patch auf Ihrem Zielcomputer mit an git apply <file>

Hinweis: Es handelt sich auch um die aktuell bereitgestellten Dateien.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Matej
quelle
Hahaha. Das ist lustig. Ich habe diese Frage vor fast vier Jahren gestellt und die Art und Weise, wie ich das gemacht habe, hat sich weiterentwickelt. Wenn Sie mich gestern gefragt hätten, wie es geht, hätte ich Ihre Antwort gegeben und gesagt, ich hätte sie aus den Antworten auf diese Frage erhalten. (Eigentlich würde ich wahrscheinlich ein nacktes git diff > save.patchund git checkout .anstelle eines Resets verwenden, aber ja ...
Malvolio
Oh, ich habe nicht bemerkt, dass es 4 Jahre alt ist: P. Übrigens soll das Zurücksetzen nur zeigen, dass es funktioniert. Ich sehe auch niemanden git apply, der den Diff für Ihren Status und den Zeiger auf das letzte verfügbare Commit verwendet oder relevant macht. Tun hat einfach git diffüberhaupt nichts getan
Matej
Ja, jetzt frage ich mich, wie ich davon erfahren habe git apply. Die Sache mit git diffist (glaube ich) von der Verwendung git reset- die Beziehungen zwischen dem Repo, dem Index und dem Arbeitsbereich sind das Problem.
Malvolio
8

Ein nützlicher Trick, um das Erstellen temporärer Patch-Dateien zu vermeiden:

git diff | patch -p1 -d [dst-dir]
langsamer Start
quelle
Genau das, was ich wollte. Funktioniert auch perfekt mit Verstecken! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
dtmland