Wie quetscht man Commits in einen Patch mit Git-Format-Patch?


163

Ich habe acht Commits in einem Zweig, die ich per E-Mail an einige Leute senden möchte, die noch nicht aufgeklärt sind. Bisher gibt mir alles, was ich mache, entweder 8 Patch-Dateien oder seit Beginn der Zeit Patch-Dateien für jedes Commit in der Geschichte des Zweigs. Ich habe git rebase --interactive verwendet, um die Commits zu quetschen, aber jetzt gibt mir alles, was ich versuche, von Anfang an zig Millionen Patches. Was mache ich falsch?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

Ich bin gespannt, welche Methode Sie am Ende unter den folgenden Aussagen anwenden werden. Lass es uns wissen;)
VonC

4
Ich werde Git Diff verwenden, wie von Rob Di Marco vorgeschlagen. Aber ich bin zwei Wochen von der Arbeit weg, nachdem ich gestern Abend die Geburt meines zweiten Mädchens miterlebt habe. Es wird also eine Weile dauern, bis ich es benutze! :)
Skiphoppy

2
Ich würde gerne Git Format-Patch sehen - Quash Master HEAD
schoetbi

1
Versuchen Sie master..HEAD, um einen Drehzahlbereich anzugeben.
Konrad Kleine

Antworten:


186

Ich würde empfehlen, dies auf einem Wegwerfzweig wie folgt zu tun. Wenn sich Ihre Commits im Zweig "Newlines" befinden und Sie bereits zu Ihrem Zweig "Master" zurückgekehrt sind, sollte dies den Trick tun:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

Hoffe das hilft!


2
Dies ist, was ich verwende, wenn ich den Verlauf lokal speichern möchte (falls ich den Patch bearbeiten muss). Ansonsten benutze ich einfach rebase -i und quetsche die Commits.
sebnow

5
für mich funktionierte es zuverlässiger mit git comit -m "My squashed commits"sonst würde es andere nicht verfolgte Dateien hinzufügen
Sebastian

Zusätzlich können Sie zu einem bestimmten Commit anstelle des Masters wechseln und dies tun, um einen Patch von Commit zu Commit zu erstellen:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.

131

Nur um dem Topf noch eine Lösung hinzuzufügen: Wenn Sie diese stattdessen verwenden:

git format-patch master --stdout > my_new_patch.diff

Dann sind es immer noch 8 Patches ... aber alle befinden sich in einer einzigen Patchdatei und gelten als eine mit:

git am < my_new_patch.diff

13
Ich mag diese Lösung. Es ist erwähnenswert, dass es manchmal einen viel größeren Patch als die von @Adam Alexander beschriebene Methode erzeugt. Dies liegt daran, dass einige Dateien möglicherweise mehrmals durch Commits bearbeitet werden. Diese Methode behandelt jedes Commit separat, selbst wenn eine Datei zurückgesetzt wurde. Meistens ist dies jedoch kein Problem.
Gumik

1
Diese Option ist ideal, wenn Sie versuchen, das Zusammenführen zu vermeiden! (zB möchten Sie einige Commits überspringen). Sie können git rebase -i ...sie alle stillen und zu einem zerquetschen.
Jorge Orpinel

21

Ich benutze immer Git Diff, also in deinem Beispiel so etwas wie

git diff master > patch.txt

15
Außer Sie verlieren alle Festschreibungsnachrichten und Metadaten. Das Schöne am Git-Format-Patch ist, dass es möglich ist, den gesamten Zweig aus einer Reihe von Patches zu rekonstruieren.
Mcepl

Die Create-Branch-and-Squash-Methode hat den Vorteil, dass alle Commit-Nachrichten zu einer zusammengefasst werden. Diese Methode ist jedoch viel schneller, wenn Sie Ihre eigene Commit-Nachricht schreiben möchten
woojoo666

git log
Tatsächlich

2
Gute Option, aber bedenken Sie, dass 'git diff' keine binären Unterschiede enthalten kann (vielleicht gibt es eine Option, um dies zu tun).
Santiago Villafuerte

18

Dies ist eine Anpassung der Antwort von Adam Alexander, falls sich Ihre Änderungen im Hauptzweig befinden. Dies tun die folgenden:

  • Erstellt einen neuen Wegwerfzweig "tmpsquash" ab dem gewünschten Punkt (suchen Sie nach dem SHA-Schlüssel, auf dem "git --log" oder mit gitg ausgeführt wird. Wählen Sie das Commit aus, das Sie als tmpsquash head verwenden möchten. Die Commits, die danach im Master ausgeführt werden, sind die gequetschten Commits).
  • Führt die Änderungen von Master zu tmpsquash zusammen.
  • Übernimmt die gequetschten Änderungen in tmpsquash.
  • Erstellt den Patch mit den gequetschten Commits.
  • Geht zurück zum Hauptzweig

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

Das Vornehmen von Änderungen am Master ist ein Anti-Pattern, wenn Sie sie nicht selbst auf die Fernbedienung übertragen. Und wenn Sie so wollen, müssen Sie wahrscheinlich keine Patch-Dateien für sie generieren.
ivan_pozdeev

18

Wie Sie bereits wissen, erhalten git format-patch -8 HEADSie mit a acht Patches.

Wenn Sie möchten, dass Ihre 8 Commits als eins angezeigt werden und es Ihnen nichts ausmacht, den Verlauf Ihres Zweigs ( o-o-X-A-B-C-D-E-F-G-H) neu zu schreiben , können Sie:

git rebase -i
// squash A, B, C, D, E ,F, G into H

oder, und es wäre eine bessere Lösung, alle 8 Commits von X(das Commit vor Ihren 8 Commits) in einem neuen Zweig wiederzugeben

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

Auf diese Weise haben Sie nur ein Commit im Zweig "Zustellung" und es repräsentiert alle Ihre letzten 8 Commits


git merge mastermacht nur einen schnellen Vorlauf und quetscht keine Commits in einen. Wechseln Sie zu git merge --squash master, um alle Commits zu quetschen und im bereitgestellten Bereich sichtbar zu machen. Ihr Flow wird mit dieser Änderung funktionieren. (Ich benutze Git Version 2.1.0.)
Stunner

5

Format-Patch zwischen zwei Tags:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

5

Am einfachsten ist es git diff, git logdie kombinierte Festschreibungsnachricht zu verwenden und hinzuzufügen , die die Squash-Methode ausgeben würde. So erstellen Sie beispielsweise den Patch zwischen Commit abcdund 1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

Dann beim Anwenden des Patches:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

Vergessen Sie nicht das --binaryArgument, git diffwenn Sie mit Nicht-Textdateien, z. B. Bildern oder Videos, arbeiten.


0

Basierend auf Adam Alexanders Antwort:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
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.