Führen Sie alle Änderungen eines anderen Zweigs (mit Squash) zu einem einzigen Commit zusammen

479

Gibt es in Git eine Möglichkeit, alle Änderungen von einem Zweig in einen anderen zusammenzuführen, aber gleichzeitig zu einem einzigen Commit zu quetschen?

Ich arbeite oft an einer neuen Funktion in einem separaten Zweig und werde regelmäßig festschreiben / pushen - hauptsächlich zur Sicherung oder um das, woran ich arbeite, auf einen anderen Computer zu übertragen. Meistens sagen diese Commits "Feature xxx WIP" oder etwas Redundantes.

Sobald diese Arbeit abgeschlossen ist und ich den WIP-Zweig wieder in den Master zusammenführen möchte, möchte ich alle diese Zwischen-Commits verwerfen und nur ein einziges sauberes Commit durchführen.

Gibt es eine einfache Möglichkeit, dies zu tun?

Wie wäre es alternativ mit einem Befehl, der alle Commits für einen Zweig seit dem Punkt, an dem er verzweigt wurde, unterdrückt?

Brad Robinson
quelle

Antworten:

601

Eine andere Option ist git merge --squash <feature branch>dann endlich eine git commit.

Von Git zusammenführen

--squash

--no-squash

Erstellen Sie den Arbeitsbaum und den Indexstatus so, als ob eine echte Zusammenführung stattgefunden hätte (mit Ausnahme der Zusammenführungsinformationen), führen Sie jedoch keine Festschreibung durch oder verschieben Sie den HEADDatensatz noch $GIT_DIR/MERGE_HEAD, um den nächsten git commitBefehl zum Erstellen einer Zusammenführungsüberschreibung zu veranlassen. Auf diese Weise können Sie ein einzelnes Commit über dem aktuellen Zweig erstellen, dessen Effekt dem Zusammenführen eines anderen Zweigs entspricht (oder mehr im Fall eines Oktopus).

fseto
quelle
1
Coole Funktion! Ich liebe Git. Obwohl ich dies jetzt definitiv in Zukunft verwenden werde, würde ich dennoch empfehlen, sich mit Rebase -i vertraut zu machen. Es ist eine gute Fähigkeit, nur für den Fall, dass Sie wirklich mehr als nur ein Commit machen wollten.
Will Buck
4
Ein Wort der Vorsicht: Dies funktioniert, aber die Standard-Festschreibungsnachricht enthält das Protokoll des zusammengeführten Zweigs. Das Problem ist, dass es dem Format ähnelt, das normalerweise angezeigt wird, wenn der gesamte angezeigte Text nicht tatsächlich Teil der Festschreibungsnachricht wird, in diesem Fall jedoch. Wenn Sie das alles nicht möchten, müssen Sie alles manuell aus Ihrer Commit-Nachricht entfernen. Ich hätte das testen sollen, bevor ich es benutzt habe ...
still_dreaming_1
23
Seien Sie gewarnt, dass der Zweig nicht als zusammengeführt angesehen wird. stackoverflow.com/questions/19308790/…
Ryan
3
IMHO sollte dies genannt worden seinrebase --squash
Andy
(da der Feature-Zweig nicht wirklich zusammengeführt wird) ist dies angemessen, wenn Sie den Feature-Zweig nach dem Festschreiben löschen möchten. Ist das korrekt? (Ich bin kein Git-Experte)
Andrew Spencer
214

Fand es! Der Befehl Zusammenführen hat eine --squashOption

git checkout master
git merge --squash WIP

An diesem Punkt wird alles zusammengeführt, möglicherweise in Konflikt geraten, aber nicht begangen. So kann ich jetzt:

git add .
git commit -m "Merged WIP"
Brad Robinson
quelle
2
Was bedeutet das git add .tun?
Michael Potter
1
@ MichaelPotter Es fügt alle Dateien und Änderungen hinzu
Daksh Shah
2
git add .Wenn alle nicht ignorierten Dateien im aktuellen Verzeichnis hinzugefügt werden, wäre ich vorsichtig, wenn ich auf diese Weise unbeabsichtigte Dateien abrufen würde.
Jake Cobb
7
Alternativ git add .können Sie git add -unur Dateien hinzufügen, die bereits zum Baum hinzugefügt wurden.
Brandon Ogle
19
Schlagen vor, dass ein "Git hinzufügen". getan werden ist auch verwirrend. Wenn ich den "git merge --squash WIP" mache, hat er bereits die gequetschten Änderungen im Index. Alles was benötigt wird, ist sie zu verpflichten. Ein "git add" machen. fügt Änderungen hinzu, die sich zufällig im Arbeitsverzeichnis befinden, aber nicht Teil des Feature-Zweigs waren. Die Frage war, wie die Änderungen im Feature-Zweig als ein Commit festgeschrieben werden können.
John Pankowicz
30

Probieren Sie git rebase -i masterIhren Feature-Zweig aus. Sie können dann alle bis auf eine Auswahl in "Squash" ändern, um die Commits zu kombinieren. Siehe Squashing Commits mit Rebase

Schließlich können Sie die Zusammenführung vom Hauptzweig aus durchführen.

fseto
quelle
8
Ja, das funktioniert, aber ich möchte nicht den Aufwand einer interaktiven Rebase. Ich will einfach alles, da der Ast abgeflacht ist.
Brad Robinson
2
+1 Dies sorgt für eine saubere Geschichte. Es ist viel einfacher, Commits als einzelne Patches, Karten, Storys usw. zu identifizieren und zu verwalten
Ryan
2

Die Verwendung git merge --squash <feature branch>als akzeptierte Antwort schlägt den Trick vor, zeigt jedoch nicht an, dass der zusammengeführte Zweig tatsächlich zusammengeführt wurde.

Eine noch bessere Lösung ist daher:

  • Erstellen Sie einen neuen Zweig vom neuesten Master
  • Verschmelzen Sie <feature branch>mitgit merge --squash
  • Führen Sie den neu erstellten Zweig zum Master zusammen

Dieses Wiki erklärt die Vorgehensweise im Detail.

raratiru
quelle
0

Ich habe meinen eigenen Git-Alias ​​erstellt, um genau dies zu tun. Ich nenne es git freebase! Ihr vorhandener unordentlicher, nicht wiederherstellbarer Feature-Zweig wird neu erstellt, sodass er zu einem neuen Zweig mit demselben Namen wird, dessen Commits zu einem Commit zusammengefasst und auf den von Ihnen angegebenen Zweig (standardmäßig Master) neu basiert werden. Ganz am Ende können Sie eine beliebige Commit-Nachricht für Ihren neuen "freebased" -Zweig verwenden.

Installieren Sie es, indem Sie den folgenden Alias ​​in Ihre .gitconfig einfügen:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Verwenden Sie es aus Ihrem Feature-Zweig, indem Sie Folgendes ausführen: git freebase <new-base>

Ich habe dies nur ein paar Mal getestet. Lesen Sie es also zuerst und stellen Sie sicher, dass Sie es ausführen möchten. Als kleine Sicherheitsmaßnahme wird der Start-sha1 gedruckt, sodass Sie Ihren alten Zweig wiederherstellen können sollten, wenn etwas schief geht.

Ich werde es in meinem Dotfiles-Repo auf Github pflegen: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig

Stephen Crosby
quelle
arbeitete wie eine Glückseligkeit! Sie können auch einen Blick auf evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/… werfen
Ilya Sheershoff
-1

git merge --squash <feature branch> ist eine gute Option. Das "Git Commit" zeigt Ihnen alle Feature Branch Branch Commit-Nachrichten mit Ihrer Wahl, um es zu behalten.

Für weniger Commit Merge.

git merge do x times --git reset HEAD ^ --soft dann git commit.

Vom Risiko gelöschte Dateien werden möglicherweise zurückgegeben.

Arjun Mullick
quelle
-5

Sie können dies mit dem Befehl "rebase" tun. Nennen wir die Zweige "main" und "feature":

git checkout feature
git rebase main

Der Befehl rebase gibt alle Commits für "feature" als ein Commit mit einem übergeordneten Element ab, das gleich "main" ist.

Möglicherweise möchten Sie git merge mainvorher ausführen, git rebase mainwenn sich "main" seit der Erstellung von "feature" (oder seit der letzten Zusammenführung) geändert hat. Auf diese Weise haben Sie immer noch Ihre vollständige Historie, falls Sie einen Zusammenführungskonflikt hatten.

Nach der Rebase können Sie Ihren Zweig mit main zusammenführen, was zu einer schnellen Zusammenführung führen sollte:

git checkout main
git merge feature

Eine gute Übersicht finden Sie auf der Rebase- Seite von Git Conceptually

NamshubWriter
quelle
Das hat bei mir nicht funktioniert. Ich habe gerade ein einfaches Test-Repo mit einem WIP-Zweig erstellt und das oben Genannte ausprobiert und Zusammenführungskonflikte erhalten (obwohl ich am Master keine Änderungen vorgenommen hatte).
Brad Robinson
Wenn das Feature aus main erstellt wurde (git checkout -b feature main) und Sie kürzlich aus main zusammengeführt wurden, sollten Sie keine Konflikte von der Rebase erhalten
NamshubWriter
OK, versuchte es erneut. Diesmal gab es keine Konflikte, aber die Geschichte wurde nicht gequetscht.
Brad Robinson
Wenn Sie sich die Git-Merge-Dokumentation noch einmal ansehen, haben Sie Recht, einige der Commits bleiben erhalten. Wenn Sie zuvor Zusammenführungen von "main" zu "feature" durchgeführt haben, werden einige, aber nicht alle von der Rebase entfernt.
NamshubWriter
Denken Sie daran, dass eine erneute Basierung sehr gefährlich sein kann, wenn der Feature-Zweig zuvor veröffentlicht wurde. Weitere Infos zu dieser SO-Frage .
Robert Rossmann