Was ist der Unterschied zwischen git merge
und git rebase
?
Antworten
Zu viele Anzeigen?Angenommen, ursprünglich gab es 3 Commits, A
,B
,C
:
Dann hat Entwickler Dan den Commit D
erstellt und Entwickler Ed den Commit E
:
Offensichtlich sollte dieser Konflikt irgendwie gelöst werden. Dafür gibt es 2 Möglichkeiten:
MERGE:
Sowohl die Commits D
und E
sind immer noch hier, aber wir erstellen den Merge-Commit M
, der Änderungen sowohl von D
als auch von E
übernimmt. Dies führt jedoch zu einer Raute, die viele Menschen sehr verwirrend finden.
REBASE:
Wir erstellen den Commit R
, dessen tatsächlicher Dateiinhalt mit dem des Merge-Commits M
oben identisch ist. Aber wir entfernen den Commit E
, als ob er nie existiert hätte (durch Punkte dargestellt - verschwindende Linie). Aufgrund dieser Auslöschung sollte E
lokal für Entwickler Ed bleiben und hätte niemals in ein anderes Repository übertragen werden dürfen. Der Vorteil des Rebase ist, dass die Rauten-Form vermieden wird und die Historie schön gerade verläuft - das mögen die meisten Entwickler!
Persönlich finde ich die Standard-Diagrammiertechnik nicht sehr hilfreich - die Pfeile scheinen immer in die falsche Richtung zu zeigen. (Sie zeigen im Allgemeinen in Richtung des "Elternteils" jedes Commits, was rückwärts in der Zeit endet, was seltsam ist).
Um es in Worte zu fassen:
- Wenn du deinen Zweig auf ihren Zweig rebasest, sagst du Git, dass es so aussehen soll, als hättest du ihren Zweig sauber ausgecheckt und dann mit deiner Arbeit von dort aus begonnen. Das erstellt ein sauberes, konzeptionell einfaches Paket von Änderungen, das jemand überprüfen kann. Du kannst diesen Prozess wiederholen, wenn es neue Änderungen an ihrem Zweig gibt, und du wirst immer mit einem sauberen Satz von Änderungen am "Kopf" ihres Zweiges enden.
- Wenn du ihren Zweig in deinen Zweig mergest, verknüpfst du die beiden Zweig-Historien an diesem Punkt miteinander. Wenn du dies später mit weiteren Änderungen erneut tust, beginnst du, ein ineinander greifendes Fadenmuster von Historien zu erstellen: einige ihrer Änderungen, einige meiner Änderungen, einige ihrer Änderungen. Einige Leute finden das unordentlich oder unerwünscht.
Aus Gründen, die ich nicht verstehe, haben GUI-Tools für Git nie viel Mühe darauf verwendet, Merge-Historien sauberer darzustellen, wobei die Einzel-Merges abstrahiert sind. Wenn du also eine "saubere Historie" haben möchtest, musst du rebase verwenden.
Ich erinnere mich, Blog-Beiträge von Programmierern gelesen zu haben, die nur rebase verwenden, und andere, die nie rebase verwenden.
Beispiel
Ich werde versuchen, dies anhand eines reinen Beispiels zu erklären. Angenommen, andere Personen in deinem Projekt arbeiten an der Benutzeroberfläche und du schreibst die Dokumentation. Ohne rebase könnte deine Historie folgendermaßen aussehen:
Tutorial schreiben
Merge remote-tracking Zweig 'origin/master' in fixdocs
Größere Schaltflächen
Dropdown-Liste
README erweitern
Merge remote-tracking Zweig 'origin/master' in fixdocs
Fenster vergrößern
Fehler in howto.md korrigieren
Das heißt, Merges und UI-Commits inmitten deiner Dokumentationscommits.
Wenn du deinen Code anstatt ihn zu mergen auf den Master rebasest, würde es so aussehen:
Tutorial schreiben
README erweitern
Fehler in howto.md korrigieren
Größere Schaltflächen
Dropdown-Liste
Fenster vergrößern
All deine Commits sind oben (neueste), gefolgt von dem Rest des master
Zweiges.
(Haftungsausschluss: Ich bin der Autor des Beitrags "10 Dinge, die ich an Git hasse", auf den eine andere Antwort Bezug nimmt)
Obwohl die akzeptierte und am meisten hochbewertete Antwort großartig ist, finde ich es hilfreich zu versuchen, den Unterschied nur mit Worten zu erklären:
merge
- „Okay, wir haben zwei unterschiedlich entwickelte Zustände unseres Repositories. Lass sie uns zusammenführen. Zwei Eltern, ein resultierendes Kind.“
rebase
- „Gib die Änderungen des Haupt-Zweigs (wie auch immer er heißt) meinem Feature-Zweig. Tue dies, indem du vorgibst, dass meine Feature-Arbeit später begonnen hat, tatsächlich aber im aktuellen Zustand des Haupt-Zweigs begonnen hat.“
- „Schreibe die Geschichte meiner Änderungen so um, dass sie das reflektieren.“ (müssen sie erzwingen, denn normalerweise geht es bei der Versionierung darum, die gegebene Geschichte nicht zu verändern)
- „Wahrscheinlich - wenn die Änderungen, die ich eingeholt habe, wenig mit meiner Arbeit zu tun haben - wird sich die Geschichte tatsächlich nicht viel ändern, wenn ich meinen Commits Diff für Diff betrachte (du kannst auch an „Patches“ denken).“
Zusammenfassung: Wenn möglich, ist rebase fast immer besser. Dies erleichtert die Wiedereingliederung in den Hauptzweig.
Weil? Deine Feature-Arbeit kann als eine große „Patch-Datei“ (auch bekannt als Diff) im Vergleich zum Hauptzweig präsentiert werden, ohne mehrere Eltern 'erklären' zu müssen: Mindestens zwei, die aus einem Zusammenführen stammen, aber wahrscheinlich viel mehr, wenn es mehrere Zusammenführungen gab. Im Gegensatz zu Merges addieren sich multiple Rebasen nicht. (ein weiterer großer Pluspunkt)
Git Rebase liegt näher an einem Merge. Der Unterschied beim Rebase ist:
- Die lokalen Commits werden temporär aus dem Branch entfernt.
- Führen Sie den Git Pull aus
- Fügen Sie alle Ihre lokalen Commits wieder ein.
Das bedeutet, dass alle Ihre lokalen Commits ans Ende verschoben werden, nach allen Remote-Commits. Wenn es zu einem Merge-Konflikt kommt, müssen Sie diesen auch lösen.
Was ist der Unterschied zwischen merge
und rebase
?
Laut dem offiziellen Git-Handbuch heißt es, dass „rebase wendet Commits auf einem anderen Basiszweig erneut an“, während „merge zwei oder mehr Entwicklungshistorien zusammenführt“. Mit anderen Worten, der Hauptunterschied zwischen merge und rebase ist, dass während merge
die Geschichte so bewahrt, wie es passiert ist, rebase
sie neu schreibt.
Lassen Sie uns diese Aussagen mit einem Beispiel nebeneinander betrachten!
Wie oben dargestellt, verflocht die merge
-Operation die Zweige, indem sie einen neuen einzelnen Merge-Commit (C7) erstellte, was zu einer diamantförmigen nicht-linearen Geschichte führte – im Grunde genommen die Geschichte so bewahrend, wie sie passiert ist. Im Vergleich dieses Ergebnisses mit dem Ergebnis der rebase
-Aktion sehen wir, dass kein Merge-Commit erstellt wurde, stattdessen wurden die beiden Commits C5 und C6 einfach zurückgesetzt und direkt oben auf C4 erneut angewendet, wodurch die Geschichte linear bleibt.
Wenn wir die beiden erneut angewendeten Commits genauer untersuchen, können wir sehen, dass sich die Hashes geändert haben, was darauf hindeutet, dass rebase
die Geschichte tatsächlich neu schreibt.
Wichtig zu beachten
Immer wenn Sie einen Zweig rebase
, werden neue Commits generiert, auch wenn der Inhalt möglicherweise gleich bleibt! Trotzdem werden frühere Commits (nach Garbage Collection) aus der Historie gelöscht, wenn keine andere Referenz (Zweig/Tag) auf sie verweist.
Mit großer Macht kommt große Verantwortung
Wir haben gesehen, wie rebase die Geschichte neu schreibt, während merge sie bewahrt. Aber was bedeutet das im weiteren Sinne? Und welche Möglichkeiten und potenzielle Nachteile bringen die beiden Operationen mit sich?
Widersprüchliche Änderungen
Angenommen, Sie hatten einige unangenehme Konflikte beim Integrieren der Änderungen. Im Merge-Szenario hätten Sie die Konflikte nur einmal, direkt im C7-Commit, lösen müssen. Mit rebase hingegen hätten Sie möglicherweise ähnliche Konflikte in jedem Commit lösen müssen (C5 und C6), da sie erneut angewendet wurden.
Veröffentlichte Zweige
Ein weiteres potenzielles Problem im Zusammenhang mit rebase tritt auf, wenn der zu rebasende Zweig bereits remote veröffentlicht wurde und jemand anderes seine Arbeit darauf aufgebaut hat. Dann kann Ihr gerebasster Zweig für alle Beteiligten zu ernsthaften Verwirrungen und Kopfschmerzen führen, da Git Ihnen mitteilt, dass Ihr Zweig sowohl vorne als auch hinten liegt. In diesem Fall löst das Ziehen von Remote-Änderungen unter Verwendung der Rebase-Flagge (git pull --rebase) in der Regel das Problem.
Darüber hinaus müssen Sie immer, wenn Sie einen bereits veröffentlichten Zweig rebasen, auch wenn niemand sonst seine Arbeit darauf aufgebaut hat, ihn mit force push auf den Remote-Server schieben, um Ihre Updates vollständig zu überschreiben.
Datenverlust (zu Ihrem Vorteil)
Zuletzt, da rebase die Geschichte neu schreibt, während merge sie bewahrt, ist es möglich, tatsächlich Daten zu verlieren, wenn Sie rebasen. Wenn neue Commits erneut angewendet werden, werden die alten (nach Garbage Collection) gelöscht. Diese Eigenschaft macht rebase tatsächlich so mächtig – sie ermöglicht es Ihnen, Ihre Entwicklungshistorie aufzuräumen, bevor Sie sie öffentlich zugänglich machen!
Schlussfolgerung
Während merge
aus Datenschutzgründen sicher ist und sich möglicherweise einfacher zu verwenden anfühlt, gibt es einige Hinweise, die Ihnen helfen können, die häufigsten Probleme im Zusammenhang mit rebase
zu vermeiden.
- Rebasen Sie keinen Zweig, der bereits remote veröffentlicht wurde...
- … es sei denn, Sie wissen, dass nur Sie daran arbeiten (und sich sicher fühlen, force push zu betätigen)
- Erstellen Sie vor dem Rebasen einen Backup-Zweig vom Spitzenzweig, den Sie rebasen möchten, da dies es Ihnen ermöglicht, das Ergebnis leicht zu vergleichen (nach dem Abschluss) und zum Vor-Rebase-Zustand zurückzugreifen, wenn nötig.
Quelle: Der obige Auszug stammt aus diesem ausführlichen Beitrag zum Thema: Unterschiede zwischen Git Merge und Rebase – und warum es wichtig ist
- See previous answers
- Weitere Antworten anzeigen