Was bedeutet es, Commits in Git zu quetschen?

116

Was bedeutet Squashing Commits in Git? Wie quetsche ich Commits in Github?

Ich bin neu bei Git und habe darum gebeten, einem Newcomer-Fehler im Coala-Analyzer zugewiesen zu werden. Ich habe den Fehler behoben und wurde nun gebeten, meine Commits zu quetschen. Wie mache ich es?

Lakshmanan Meiyappan
quelle
Hey @Lakshman, zögern Sie nicht, die Antwort mit der höchsten Stimme anzunehmen. Es beantwortet Ihre Frage richtig.
Mostafiz Rahman

Antworten:

179

Sie können sich Git als erweiterte Datenbank mit Snapshots Ihrer Arbeitsverzeichnisse vorstellen.

Eine sehr schöne Funktion von Git ist die Möglichkeit, den Verlauf von Commits neu zu schreiben.
Der Hauptgrund dafür ist, dass ein Großteil dieses Verlaufs nur für den Entwickler relevant ist, der ihn generiert hat. Daher muss er vereinfacht oder verbessert werden, bevor er an ein freigegebenes Repository gesendet wird.

Das Quetschen eines Commits bedeutet aus idiomatischer Sicht, die in diesem Commit eingeführten Änderungen in das übergeordnete Commit zu verschieben, sodass Sie ein Commit anstelle von zwei (oder mehr) erhalten.
Wenn Sie diesen Vorgang mehrmals wiederholen, können Sie n Commit auf einen einzigen reduzieren .

Wenn Sie Ihre Arbeit mit dem Commit-Tag Start begonnen haben , möchten Sie dies visuell

Git begeht Squashing

Möglicherweise stellen Sie fest, dass das neue Commit einen etwas dunkleren Blauton aufweist. Dies ist beabsichtigt.

In Git wird Squashing mit einer Rebase in einer speziellen Form namens Interactive Rebase erreicht .
Wenn Sie eine Reihe von Commits in einen Zweig B umwandeln , wenden Sie vereinfacht alle Änderungen an, die durch diese Commits vorgenommen wurden, beginnend mit B anstelle ihres ursprünglichen Vorfahren.

Ein visueller Hinweis

Geben Sie hier die Bildbeschreibung ein

Beachten Sie noch einmal die verschiedenen Blautöne.

Mit einer interaktiven Rebase können Sie auswählen, wie Commits neu basiert werden sollen. Wenn Sie diesen Befehl ausführen:

 git rebase -i branch

Am Ende erhalten Sie eine Datei, in der die festgeschriebenen Commits aufgeführt sind

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

Ich habe die Commits nicht benannt, aber diese vier sollen die Commits von Start bis Head sein

Das Schöne an dieser Liste ist, dass sie bearbeitet werden kann .
Sie können Commits weglassen oder sie quetschen .
Alles was Sie tun müssen, ist das erste Wort in Squash zu ändern .

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

Wenn Sie den Editor schließen und keine Zusammenführungskonflikte gefunden werden, erhalten Sie diesen Verlauf:

Geben Sie hier die Bildbeschreibung ein

In Ihrem Fall möchten Sie nicht auf einen anderen Zweig zurückgreifen, sondern auf einen vorherigen Commit.
Um den Verlauf wie im ersten Beispiel gezeigt zu transformieren, müssen Sie so etwas wie ausführen

git rebase -i HEAD~4

Ändern Sie die "Befehle" in " Squash" für alle Commits außer dem ersten und schließen Sie dann Ihren Editor.


Hinweis zum Ändern des Verlaufs

In Git werden Commits niemals bearbeitet. Sie können beschnitten, nicht erreichbar gemacht, geklont, aber nicht verändert werden.
Wenn Sie die Basis neu festlegen, erstellen Sie tatsächlich neue Commits.
Die alten sind für Schiedsrichter nicht mehr erreichbar, werden also nicht in der Geschichte angezeigt, sind aber immer noch da!

Dies ist, was Sie tatsächlich für eine Rebase erhalten:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie sie bereits irgendwohin geschoben haben, wird durch das Umschreiben des Verlaufs tatsächlich ein Zweig erstellt!

Margaret Bloom
quelle
Schön - was passiert mit den ursprünglichen Commit-Kommentaren - werden sie zu einem einzigen großen Commit-Kommentar zusammengefasst oder gehen sie verloren?
Paul R
Von man git rebase: Die vorgeschlagene Festschreibungsnachricht für die gefaltete Festschreibung ist die Verkettung der Festschreibungsnachrichten der ersten Festschreibung und derjenigen mit dem Befehl "Squash"
Margaret Bloom
1
Dies ist die beste Erklärung, die ich für die Umbasierung gesehen habe, danke.
Kerry Jones
Informationen zum Quetschen in Ihrem ersten Bild: Können Sie ein Beispiel anführen, in dem HEAD vor (hellblau) und nach (dunkelblau) dem Quetschen ein anderes Arbeitsverzeichnis hat? In allen Beispielen, in denen ich versucht habe zu quetschen, sah es so aus, als hätte es nur die drei Commits zwischen START und HEAD gelöscht.
actual_panda
@actual_panda Ich bin nicht sicher, ob ich folge. HEAD ist ein Ref zu einem Commit. Commits speichern Deltas. Das Arbeitsverzeichnis ist eine Eigenschaft des gesamten Repositorys. Dies hängt davon ab, welches Commit Sie ausgecheckt haben. Im Allgemeinen geben zwei Refs (wie HEAD und START) beim Auschecken immer zwei verschiedene Workdirs an. Wenn Sie Squash auf demselben Zweig neu aufbauen, führt dies dazu, dass die Zwischen-Commits "verloren" werden. In Wirklichkeit hat git jedoch einen neuen mit allen Deltas erstellt. git diffkann Ihnen helfen zu zeigen, was passiert ist.
Margaret Bloom
22

Der Rebase-Befehl bietet einige fantastische Optionen im --interactive(oder -i) Modus, und eine der am häufigsten verwendeten ist die Fähigkeit, Commits zu quetschen. Dies führt dazu, dass kleinere Commits zu größeren zusammengefasst werden. Dies kann hilfreich sein, wenn Sie die Arbeit des Tages abschließen oder Ihre Änderungen nur anders verpacken möchten. Wir werden darüber nachdenken, wie Sie dies einfach tun können.

Ein Wort der Vorsicht: Tun Sie dies nur bei Commits, die nicht in ein externes Repository verschoben wurden. Wenn andere auf den Commits basieren, die Sie löschen möchten, können viele Konflikte auftreten. Schreiben Sie Ihren Verlauf nur nicht neu, wenn er mit anderen geteilt wurde.

Nehmen wir also an, Sie haben gerade ein paar kleine Commits gemacht und möchten daraus ein größeres Commit machen. Die Geschichte unseres Repositorys sieht derzeit folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

Die letzten 4 Commits wären viel glücklicher, wenn sie zusammengepackt würden. Lassen Sie uns genau das durch interaktives Rebasing tun:

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Hier sind also ein paar Dinge passiert. Zuerst sagte ich Git, dass ich mit den letzten vier Commits, von denen aus sich HEAD mit HEAD ~ 4 befindet, eine Rebase erstellen wollte. Git hat mich jetzt in einen Editor mit dem obigen Text und einer kleinen Erklärung dessen, was getan werden kann, versetzt. Auf diesem Bildschirm stehen Ihnen zahlreiche Optionen zur Verfügung, aber im Moment werden wir nur alles in einem Commit zusammenfassen. Wenn Sie also die ersten vier Zeilen der Datei in diese ändern, reicht dies aus:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

Grundsätzlich weist dies Git an, alle vier Commits zum ersten Commit in der Liste zu kombinieren. Sobald dies erledigt und gespeichert ist, wird ein anderer Editor mit den folgenden Optionen angezeigt:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

Da wir so viele Commits kombinieren, können Sie mit Git die Nachricht des neuen Commits basierend auf den übrigen am Prozess beteiligten Commits ändern. Bearbeiten Sie die Nachricht nach Belieben, speichern Sie sie und beenden Sie sie. Sobald dies erledigt ist, wurden Ihre Commits erfolgreich gequetscht!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

Und wenn wir uns die Geschichte noch einmal ansehen ... Geben Sie hier die Bildbeschreibung ein

Das war bisher relativ schmerzlos. Wenn Sie während der Rebase auf Konflikte stoßen, sind diese normalerweise recht einfach zu lösen und Git führt Sie so weit wie möglich durch. Die Grundlagen hierfür sind, den fraglichen Konflikt, git adddie Datei, zu beheben und dann git rebase --continueden Vorgang fortzusetzen. git rebase --abortWenn Sie a ausführen, kehren Sie natürlich zu Ihrem vorherigen Zustand zurück, wenn Sie möchten. Wenn Sie aus irgendeinem Grund ein Commit in der Rebase verloren haben, können Sie das Reflog verwenden, um es zurückzubekommen.

Details finden Sie unter diesem Link .

0xAliHn
quelle
3
Danke dir! Wenn sich jemand mit VIM genauso unwohl fühlt wie ich ... Wenn Sie an dem Punkt angelangt sind, an dem Sie die zu bearbeitenden Aktionen eingeben, drücken Sie 'i', um den Bearbeitungsmodus aufzurufen. Wenn Sie mit den Änderungen fertig sind, drücken Sie die Esc-Taste und geben Sie ": wq" ein. Dadurch werden Sie vorwärts gebracht. (Mac)
Farasi78
+1 für die Vorsicht und den Kontext, wann dies zu tun ist. Nach meiner persönlichen Erfahrung ist es gut, wenn Sie alleine an einem Feature-Zweig arbeiten und eine Menge trivialer Commits wie "aktualisierte Readme-Datei", "etwas getan haben, das niemanden interessiert" haben und bereit sind, den Zweig zusammenzuführen Nun, quetschen Sie diese alle in einem Commit. Niemand wird zu Ihrem "hat etwas getan, das niemanden interessiert" zurückkehren wollen und es verschmutzt die Commit-Geschichte
Adam Hughes