Wann wird die Verwendung von git rebase
vs. git merge
empfohlen?
Muss ich nach einer erfolgreichen Rebase noch zusammenführen?
Wann verwendest du eines?
Mit rebase ist es einfach, einen anderen Zweig als neuen base für Ihre Arbeit zu verwenden.
Wenn Sie beispielsweise über einen Zweig master
verfügen und einen Zweig erstellen, um ein neues Feature zu implementieren, nennen Sie es cool-feature
.
Nun möchten Sie an einem bestimmten Punkt die neue Funktion hinzufügen, die Sie im Zweig master
implementiert haben. Sie könnten einfach zu master
wechseln und den cool-feature
-Zweig zusammenführen:
$ git checkout master
$ git merge cool-feature
auf diese Weise wird jedoch ein neues Dummy-Commit hinzugefügt. Wenn Sie die Spaghetti-Geschichte vermeiden möchten, können Sie rebase :
$ git checkout cool-feature
$ git rebase master
und dann in master
zusammenführen:
$ git checkout master
$ git merge cool-feature
Da diesmal der Themenzweig die gleichen Commits von master und die Commits mit der neuen Funktion hat, ist die Zusammenführung nur ein schneller Vorlauf.
meine eigene Antwort ergänzen erwähnt von TSamper ,
eine Rebase ist oft eine gute Idee, bevor Sie eine Zusammenführung durchführen, da die Idee darin besteht, dass Sie in Ihrem Zweig Y
die Arbeit des Zweigs B
integrieren, mit dem Sie zusammenführen.
Aber bevor Sie zusammenführen, lösen Sie jeden Konflikt in Ihrem branch (d. H .: "rebase", wie in "geben Sie meine Arbeit in meinem Zweig wieder ab einem jüngsten Punkt aus dem Zweig B
).
Wenn dies korrekt ausgeführt wird, kann die nachfolgende Zusammenführung von Ihrem Zweig zu Zweig B
ein schneller Vorlauf sein.
ein Zusammenführen wirkt sich direkt auf den Zielzweig B
aus. Dies bedeutet, dass die Zusammenführungen besser trivial sind. Andernfalls kann der Zweig B
lange dauern, um wieder in einen stabilen Zustand zu gelangen (Zeit, für die Sie alle Konflikte lösen).
der Punkt der Verschmelzung nach einer Rebase?
In dem Fall, den ich beschreibe, stütze ich B
auf meinen Zweig ab, nur um die Möglichkeit zu haben, meine Arbeit von einem neueren Punkt aus B
abzuspielen, während ich in meinem Zweig bleibe.
In diesem Fall ist noch eine Zusammenführung erforderlich, um meine "wiedergegebene" Arbeit auf B
zu bringen.
Das andere Szenario ( in Git Ready beschrieben zum Beispiel) besteht darin, Ihre Arbeit direkt in B
durch eine Rebase zu bringen (die all Ihre Nice-Commits konserviert oder Ihnen sogar die Möglichkeit gibt, sie durch ein interaktives Programm neu zu ordnen.) rebase).
In diesem Fall (wenn Sie sich im B-Zweig aufhalten) haben Sie Recht: Es ist keine weitere Zusammenführung erforderlich:
Ein Git-Baum bei Standardeinstellung, wenn wir nicht zusammengeführt oder umbasiert haben
wir bekommen durch Umbasierung:
In diesem zweiten Szenario dreht sich alles um: Wie bekomme ich ein neues Feature in Master?.
Wenn ich das erste Rebase-Szenario beschreibe, möchte ich alle daran erinnern, dass eine Rebase auch als vorbereitender Schritt dazu verwendet werden kann ("das neue Feature zurück in den Master bringen").
Sie können rebase verwenden, um master zuerst in den Zweig mit neuen Features zu bringen: Die rebase gibt die neuen Feature-Commits aus dem HEAD master
wieder, aber immer noch im Zweig mit dem neuen Feature, wodurch der Startpunkt Ihrer Verzweigung effektiv von einem alten verschoben wird Master-Commit für HEAD-master
.
Damit können Sie Konflikte in Ihrem branch auflösen (dh isoliert, während Master sich parallel weiterentwickelt, wenn die Konfliktlösung zu lange dauert).
Dann können Sie zum Master wechseln und new-feature
zusammenführen (oder new-feature
in master
umbinden, wenn Sie die in Ihrem new-feature
-Zweig durchgeführten Commits beibehalten möchten).
So:
master
. Wenn Sie irgendwelche Zweifel haben, verwenden Sie Zusammenführen.
Die einzigen Unterschiede zwischen einem Rebase und einem Merge sind:
Die kurze Antwort lautet also Rebase oder Merge auswählen, je nachdem, wie Ihr Verlauf aussehen soll.
Es gibt einige Faktoren, die Sie bei der Auswahl der zu verwendenden Operation berücksichtigen sollten.
Wenn ja, nicht rebase. Durch einen Neustart wird der Zweig zerstört, und diese Entwickler haben defekte/inkonsistente Repositorys, sofern sie nicht git pull --rebase
Verwenden. Dies ist ein guter Weg, um andere Entwickler schnell zu verärgern.
Rebase ist eine destruktive Operation. Das heißt, wenn Sie es nicht korrekt anwenden , können Sie die festgelegte Arbeit verlieren und/oder die Konsistenz der Repositorys anderer Entwickler beeinträchtigen.
Ich habe in Teams gearbeitet, in denen die Entwickler alle aus einer Zeit stammten, in der sich Unternehmen engagierte Mitarbeiter für die Abwicklung von Verzweigungen und Zusammenschlüssen leisten konnten. Diese Entwickler wissen nicht viel über Git und wollen auch nicht viel wissen. In diesen Teams würde ich nicht riskieren, aus irgendeinem Grund eine Neuinstallation zu empfehlen.
Einige Teams verwenden das Branch-per-Feature-Modell, bei dem jeder Branch ein Feature (oder einen Bugfix oder ein Unterfeature usw.) darstellt. In diesem Modell hilft der Branch bei der Identifizierung von Gruppen verwandter Commits. Zum Beispiel kann ein Feature schnell zurückgesetzt werden, indem die Zusammenführung dieses Zweigs rückgängig gemacht wird (um fair zu sein, dies ist eine seltene Operation). Oder unterscheiden Sie ein Feature, indem Sie zwei Zweige vergleichen (häufiger). Ein Rebase würde den Zweig zerstören und das wäre nicht einfach.
Ich habe auch an Teams gearbeitet, die das Branch-per-Developer-Modell verwendeten (wir waren alle dabei). In diesem Fall übermittelt die Filiale selbst keine zusätzlichen Informationen (das Commit hat bereits den Autor). Ein Umbasieren würde keinen Schaden anrichten.
Das Zurücksetzen (wie beim Rückgängigmachen) einer Basis ist im Vergleich zum Zurücksetzen einer Zusammenführung erheblich schwieriger und/oder unmöglich (wenn bei der Basis Konflikte aufgetreten sind). Wenn Sie glauben, dass die Möglichkeit besteht, dass Sie zurücksetzen möchten, verwenden Sie die Option Zusammenführen.
Rebase-Operationen müssen mit einem entsprechenden git pull --rebase
Abgerufen werden. Wenn Sie alleine arbeiten, können Sie sich möglicherweise merken, welche Sie zum richtigen Zeitpunkt verwenden sollten. Wenn Sie in einem Team arbeiten, ist dies sehr schwierig zu koordinieren. Aus diesem Grund empfehlen die meisten Rebase-Workflows die Verwendung von Rebase für alle Zusammenführungen (und git pull --rebase
Für alle Pulls).
Angenommen, Sie haben die folgende Zusammenführung:
B -- C
/ \
A--------D
Einige Leute werden angeben, dass die Zusammenführung den Festschreibungsverlauf "zerstört", da Sie die wichtigen Festschreibungsnachrichten in B und C verpassen würden, wenn Sie sich nur das Protokoll des Hauptzweigs (A - D) ansehen würden.
Wenn dies wahr wäre, hätten wir nicht Fragen wie diese . Grundsätzlich sehen Sie B und C, sofern Sie nicht ausdrücklich darum bitten, sie nicht zu sehen (mit --first-parent). Dies ist sehr einfach, um es selbst zu versuchen.
Die beiden Ansätze werden unterschiedlich zusammengeführt, aber es ist nicht klar, dass einer immer besser als der andere ist und dies möglicherweise vom Entwicklerworkflow abhängt. Wenn ein Entwickler beispielsweise dazu neigt, regelmäßig Commits durchzuführen (z. B. zweimal am Tag, wenn er von der Arbeit nach Hause wechselt), gibt es möglicherweise viele Commits für eine bestimmte Branche. Viele dieser Commits sehen möglicherweise nicht wie das Endprodukt aus (ich neige dazu, meinen Ansatz ein- oder zweimal pro Feature umzugestalten). Wenn jemand anderes an einem verwandten Codebereich arbeitete und versuchte, meine Änderungen zurückzusetzen, könnte dies eine ziemlich mühsame Operation sein.
Wenn Sie rm
mit rm -rf
Aliasen möchten, um "Zeit zu sparen", dann ist Rebase vielleicht etwas für Sie.
Ich denke immer, dass ich eines Tages auf ein Szenario stoßen werde, in dem Git Rebase das großartige Tool ist, das das Problem löst. Ähnlich wie ich denke, stoße ich auf ein Szenario, in dem Git-Reflog ein großartiges Tool ist, das mein Problem löst. Ich arbeite jetzt seit über fünf Jahren mit Git. Es ist nicht passiert.
Chaotische Geschichten waren für mich nie wirklich ein Problem. Ich lese meine Commit-Geschichte nicht nur wie einen spannenden Roman. In den meisten Fällen, in denen ich eine Vorgeschichte benötige, werde ich sowieso git blame oder git bisect verwenden. In diesem Fall ist das Festschreiben der Zusammenführung für mich sehr nützlich, denn wenn die Zusammenführung das Problem verursacht, sind dies für mich aussagekräftige Informationen.
Ich fühle mich verpflichtet zu erwähnen, dass ich persönlich weniger auf Rebase gesetzt habe, obwohl meine allgemeinen Ratschläge immer noch gültig sind. In letzter Zeit habe ich viel mit dem Angular 2 Material -Projekt interagiert. Sie haben Rebase verwendet, um einen sehr sauberen Commit-Verlauf zu führen. Auf diese Weise konnte ich sehr leicht feststellen, durch welches Commit ein bestimmter Fehler behoben wurde und ob dieses Commit in einer Version enthalten war. Es ist ein großartiges Beispiel für die korrekte Verwendung von Rebase.
Viele Antworten hier besagen, dass durch das Zusammenführen alle Commits in ein Commit umgewandelt werden. Daher wird empfohlen, die Rebase zu verwenden, um die Commits beizubehalten. Das ist falsch. Und eine schlechte Idee, wenn Sie Ihre Commits bereits vorangetrieben haben .
Durch das Zusammenführen werden Ihre Commits nicht gelöscht. Merge bewahrt die Geschichte! (siehe gitk) Rebase schreibt den Verlauf neu, was eine schlechte Sache ist, nachdem Sie ihn gedrückt haben .
Verwenden Sie "Merge" - und nicht "Rebase" , wenn Sie bereits einen Push ausgeführt haben.
Hier ist Linus '(Autor von Git) übernehmen . Es ist eine wirklich gute Lektüre. Oder Sie können meine eigene Version der gleichen Idee weiter unten lesen.
Neustarten eines Zweigs auf dem Master:
Im Gegensatz dazu führt das Zusammenführen eines Zweigthemas zum Master Folgendes durch:
Zusammenführen bedeutet: Erstellen Sie ein einzelnes neues Commit, das meine Änderungen in das Ziel einfügt.
Neubasis bedeutet: Erstellen Sie eine ganze Reihe von Commits, wobei Sie meine aktuellen Commits als Hinweise verwenden. Mit anderen Worten: Berechnen Sie, wie meine Änderungen ausgesehen hätten, wenn ich angefangen hätte, sie von dem Punkt an zu machen, an dem ich mich neu orientiere. Nach dem Rebase-Test müssen Sie daher möglicherweise die Änderungen erneut testen, und während des Rebasis-Tests treten möglicherweise einige Konflikte auf.
Warum sollten Sie sich angesichts dieser Tatsache zurückhalten? Nur um die Entwicklungsgeschichte klar zu halten. Nehmen wir an, Sie arbeiten an Feature X, und wenn Sie fertig sind, führen Sie Ihre Änderungen in zusammen. Das Ziel enthält jetzt eine einzige Festschreibung, die etwas in Richtung "Hinzugefügtes Feature X" aussagt. Anstatt zu verschmelzen, würde die Zielentwicklungshistorie, wenn Sie neu basierten und dann zusammengeführt wurden, alle einzelnen Commits in einer einzigen logischen Abfolge enthalten. Das macht es später einfacher, Änderungen zu überprüfen. Stellen Sie sich vor, wie schwer es wäre, den Entwicklungsverlauf zu überprüfen, wenn 50 Entwickler ständig verschiedene Funktionen zusammenführen.
Das heißt, wenn Sie den Zweig, an dem Sie arbeiten, bereits in den Upstream-Bereich verschoben haben, sollten Sie nicht rebasieren, sondern stattdessen zusammenführen. Für Zweige, die nicht in den Upstream-Modus verschoben wurden, müssen Sie die Basis neu testen, testen und zusammenführen.
Ein anderes Mal möchten Sie möglicherweise rebasieren, wenn Sie Commits aus Ihrem Zweig entfernen möchten, bevor Sie in den Upstream-Modus gelangen. Zum Beispiel: Commits, die frühzeitig Debugging-Code einführen, und andere Commits, die diesen Code bereinigen. Die einzige Möglichkeit, dies zu tun, ist die Durchführung einer interaktiven Basis: git rebase -i <branch/commit/tag>
UPDATE: Sie möchten rebase auch verwenden, wenn Sie Git als Schnittstelle zu einem Versionskontrollsystem verwenden, das nicht-lineare Historie unterstützt (z. B. Subversion). Wenn Sie die git-svn-Bridge verwenden, ist es sehr wichtig, dass die Änderungen, die Sie wieder in Subversion zusammenführen, eine sequentielle Liste der Änderungen über den letzten Änderungen in Trunk sind. Dazu gibt es nur zwei Möglichkeiten: (1) Erstellen Sie die Änderungen manuell neu, und (2) verwenden Sie den Befehl rebase, der viel schneller ist.
UPDATE2: Eine weitere Möglichkeit, sich eine Rebase vorzustellen, besteht darin, dass sie eine Art Zuordnung von Ihrem Entwicklungsstil zu dem im Repository akzeptierten Stil ermöglicht, für den Sie sich engagieren. Nehmen wir an, Sie begehen gerne kleine, winzige Brocken. Sie haben ein Commit, um einen Tippfehler zu beheben, ein Commit, um nicht verwendeten Code zu entfernen, und so weiter. Wenn Sie alles erledigt haben, was Sie tun müssen, haben Sie eine lange Reihe von Commits. Nehmen wir an, das Repository, für das Sie sich verpflichten, zu großen Commits ermutigt. Für Ihre Arbeit würden Sie also ein oder zwei Commits erwarten. Wie nehmen Sie Ihre Commits und komprimieren sie auf das, was erwartet wird? Sie würden eine interaktive Rebase verwenden und Ihre winzigen Commits in weniger große Blöcke zerquetschen. Das Gleiche gilt, wenn das Gegenteil nötig war - wenn Ihr Stil aus ein paar großen Commits bestand, der Repo jedoch lange Strings aus kleinen Commits forderte. Sie würden auch eine Rebase verwenden, um das zu tun. Wenn Sie stattdessen zusammengeführt hatten, haben Sie jetzt Ihren Commit-Stil in das Haupt-Repository übernommen. Wenn es viele Entwickler gibt, können Sie sich vorstellen, wie schwer es wäre, nach einiger Zeit eine Historie mit verschiedenen Commit-Styles zu verfolgen.
UPDATE3: Does one still need to merge after a successful rebase?
Ja. Der Grund ist, dass eine Rebase im Wesentlichen ein "Verschieben" von Commits beinhaltet. Wie ich bereits gesagt habe, werden diese Commits berechnet. Wenn Sie jedoch 14 Commits vom Verzweigungspunkt aus gesehen haben und dann vorausgesetzt, dass mit Ihrer Rebase nichts schief geht, sind Sie 14 Commits voraus (des Punktes, auf den Sie sich basieren) die rebase ist vollbracht. Sie hatten vor einer Rebase einen Zweig. Sie haben danach einen Zweig der gleichen Länge. Sie müssen noch zusammenführen, bevor Sie Ihre Änderungen veröffentlichen. Mit anderen Worten, so viele Male wie Sie möchten (auch nur, wenn Sie Ihre Änderungen nicht in den Upstream verschoben haben). Mischen Sie erst, nachdem Sie die Datenbank neu erstellt haben.
vor dem Zusammenführen/Ersetzen:
A <- B <- C [master]
^
\
D <- E [branch]
nach git merge master
:
A <- B <- C
^ ^
\ \
D <- E <- F
nach git rebase master
:
A <- B <- C <- D' <- E'
(A, B, C, D, E und F sind Commits)
dieses beispiel und viel besser illustrierte informationen über git finden sie hier: http://excess.org/article/2008/07/07/ogre-git-tutorial/
Das Zusammenführen ist definitiv die einfachste und häufigste Möglichkeit, Änderungen zu integrieren, ist aber nicht die einzige: Rebase ist ein alternatives Integrationsmittel.
Verständnis etwas besser zusammenfügen
Wenn Git eine Zusammenführung durchführt, werden drei Commits gesucht:
Fast-Forward oder Merge Commit
In sehr einfachen Fällen hat eine der beiden Verzweigungen keine neuen Commits, da die Verzweigung stattgefunden hat - ihr letztes Commit ist immer noch der gemeinsame Vorfahr.
In diesem Fall ist das Durchführen der Integration ein Kinderspiel: Git kann nur die Commits des anderen Zweigs über das Common-Vorfahren-Commit hinzufügen. In Git wird diese einfachste Form der Integration als "Fast-Forward" -Mischung bezeichnet. Beide Zweige haben dann die gleiche Geschichte.
In vielen Fällen sind jedoch beide Zweige einzeln vorgerückt .
Um eine Integration vorzunehmen, muss Git ein neues Commit erstellen, das die Unterschiede zwischen ihnen enthält - das Merge-Commit.
Human Commits & Merge Commits
Normalerweise wird ein Commit sorgfältig von einem Menschen erstellt. Es ist eine sinnvolle Einheit, die nur verwandte Änderungen umschließt und sie mit einem Kommentar kommentiert.
Ein Merge-Commit ist etwas anders: Statt von einem Entwickler erstellt zu werden, wird es automatisch von Git erstellt. Anstatt einen Satz verwandter Änderungen einzuwickeln, besteht der Zweck darin, zwei Zweige wie einen Knoten zu verbinden. Wenn Sie eine Zusammenführungsoperation später verstehen möchten, müssen Sie sich die Historie beider Zweige und das entsprechende Commit-Diagramm ansehen.
Integration mit Rebase
Einige Leute ziehen es vor, auf solche automatischen Merge-Commits zu verzichten. Stattdessen möchten sie, dass die Projekthistorie so aussieht, als ob sie sich in einer einzigen, geraden Linie entwickelt hätte. Es gibt keine Hinweise darauf, dass es in mehrere Zweige aufgeteilt wurde Irgendwann.
Gehen wir Schritt für Schritt durch eine Rebase-Operation. Das Szenario ist das gleiche wie in den vorherigen Beispielen: Wir möchten die Änderungen von Branch-B in Branch-A integrieren, jetzt aber mit Rebase.
Wir werden dies in drei Schritten tun
git rebase branch-A // syncs the history with branch-A
git checkout branch-A // change the current branch to branch-A
git merge branch-B // merge/take the changes from branch-B to branch-A
Zuerst wird Git alle Commits auf Branch-A "rückgängig machen", nachdem die Zeilen verzweigt wurden (nach dem Common-Vorfahren-Commit). Allerdings werden sie natürlich nicht verworfen. Stattdessen können Sie sich diese Commits als "vorübergehend gespeichert" vorstellen.
Als Nächstes werden die Commits aus Branch-B übernommen, die wir integrieren möchten. Zu diesem Zeitpunkt sehen beide Zweige genau gleich aus.
Im letzten Schritt werden die neuen Commits auf Branch-A nun erneut angewendet - aber auf einer neuen Position, zusätzlich zu den integrierten Commits von Branch-B (sie basieren auf re-based) .Das Ergebnis sieht nach Entwicklung aus war in einer geraden Linie passiert. Anstelle eines Merge-Commits, das alle kombinierten Änderungen enthält, wurde die ursprüngliche Commit-Struktur beibehalten.
Schließlich erhalten Sie einen sauberen Zweig branch-A ohne unerwünschte und automatisch generierte Commits.
Hinweis: Aus dem awesome post von git-tower
. Die Nachteile von rebase
ist auch eine gute Lektüre in demselben Beitrag.
Dieser Satz bekommt es:
Im Allgemeinen können Sie das Beste aus beiden Welten erzielen, indem Sie local Änderungen, die Sie vorgenommen haben, aber noch nicht freigegeben wurden, bevor Sie sie eingeben Um Ihre Geschichte aufzuräumen, stützen Sie jedoch niemals etwas ab, was Sie schon getan haben irgendwo.
Quelle: http://www.git-scm.com/book/de/v2/Git-Branching-Rebasing#Rebase-vs.-Merge
Das Pro git-Buch als wirklich gute Erklärung auf der umbasierenden Seite .
Grundsätzlich werden bei einer Zusammenführung 2 Commits ausgeführt und kombiniert.
Eine Rebase geht zum gemeinsamen Vorfahren auf der 2 und wendet die Änderungen schrittweise übereinander an. Dies führt zu einer "saubereren" und lineareren Geschichte.
Aber wenn Sie sich zurückhalten, geben Sie frühere Commits auf und erstellen neue. Daher sollten Sie ein Repo, das öffentlich ist, niemals neu abstimmen. Die anderen Leute, die am Repo arbeiten, werden dich hassen.
Allein deshalb verschmelze ich fast ausschließlich. In 99% der Fälle unterscheiden sich meine Zweigstellen nicht so stark. Wenn es Konflikte gibt, dann nur an ein oder zwei Stellen.
Diese Antwort ist weitgehend auf Git Flow ausgerichtet. Die Tabellen wurden mit dem Nice ASCII - Tabellengenerator und die Historienbäume mit diesem wunderbaren Befehl ( Alias as git lg
) erstellt:
git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
Tabellen sind in umgekehrter chronologischer Reihenfolge, um mehr mit den Historienbäumen übereinzustimmen. Siehe auch den Unterschied zwischen git merge
und git merge --no-ff
zuerst (normalerweise möchten Sie git merge --no-ff
verwenden, da dies dazu führt, dass Ihre Geschichte der Realität näher kommt):
git merge
Befehle:
Time Branch "develop" Branch "features/foo"
------- ------------------------------ -------------------------------
15:04 git merge features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Ergebnis:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
| Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
| Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge --no-ff
Befehle:
Time Branch "develop" Branch "features/foo"
------- -------------------------------- -------------------------------
15:04 git merge --no-ff features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Ergebnis:
* 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/ Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge
vs git rebase
Erster Punkt: füge Features immer zusammen und entwickle nie, entwickle nie Features von Features. Dies ist eine Folge der Goldenen Regel der Neueinstellung :
Die goldene Regel von
git rebase
ist, es niemals in public -Zweigen zu verwenden.
Niemals etwas widerlegen, was Sie irgendwo geschoben haben.
Ich würde persönlich hinzufügen: es sei denn, es handelt sich um einen Funktionszweig UND Sie und Ihr Team sind sich der Konsequenzen bewusst.
Die Frage von git merge
vs git rebase
gilt also fast nur für die Feature-Zweige (in den folgenden Beispielen wurde --no-ff
immer beim Zusammenführen verwendet). Da ich nicht sicher bin, ob es eine bessere Lösung gibt ( eine Debatte existiert ), werde ich nur angeben, wie sich beide Befehle verhalten. In meinem Fall bevorzuge ich git rebase
, da dies einen schöneren Historienbaum erzeugt :)
git merge
Befehle:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Ergebnis:
* c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\ Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | | Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | | Fourth commit - Christophe
* | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \ Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Befehle:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git rebase features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Ergebnis:
* 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
develop
zu einem Funktionszweiggit merge
Befehle:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m “Sixth commit"
15:08 git merge --no-ff development
15:07 git merge --no-ff features/foo
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
Ergebnis:
* 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\ Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | | Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ / Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Befehle:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m “Sixth commit"
15:08 git rebase development
15:07 git merge --no-ff features/foo
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
Ergebnis:
* b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git cherry-pick
Wenn Sie nur ein bestimmtes Commit benötigen, ist git cherry-pick
eine Nice-Lösung (die -x
-Option fügt eine Zeile mit der Zeichenfolge "(Kirsche aus Commit ...)" an den ursprünglichen Nachrichtentext der Commit-Nachricht an gute Idee, es zu benutzen - git log <commit_sha1>
, um es zu sehen):
Befehle:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m “Sixth commit"
15:07 git cherry-pick -x <second_commit_sha1>
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
Ergebnis:
* 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| | Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git pull --rebase
Nicht sicher, ob ich es besser erklären kann als Derek Gourlay ... Im Allgemeinen verwenden Sie git pull --rebase
anstelle von git pull
:) Was in diesem Artikel jedoch fehlt, ist, dass Sie es standardmäßig aktivieren können :
git config --global pull.rebase true
git rerere
Wieder schön erklärt hier . Einfach ausgedrückt: Wenn Sie diese Option aktivieren, müssen Sie denselben Konflikt nicht mehrmals lösen.
Git rebase wird verwendet, um die Verzweigungspfade in der History-Cleaner- und Repository-Struktur linear zu machen.
Es wird auch verwendet, um die von Ihnen erstellten Verzweigungen privat zu halten, da nach dem Umbasieren und Übertragen der Änderungen auf den Server beim Löschen Ihrer Verzweigung kein Hinweis auf eine Verzweigung vorliegt, an der Sie gearbeitet haben. So ist Ihre Niederlassung jetzt Ihr lokales Anliegen.
Nachdem wir rebase gemacht haben, entfernen wir auch ein zusätzliches Commit, das wir bei normaler Zusammenführung überprüft haben.
Und ja, man muss nach einem erfolgreichen Rebase-Vorgang immer noch zusammenführen, da der Rebebankommando Ihre Arbeit nur auf den Zweig setzt, den Sie während des Rebebase-Befehls erwähnt haben, beispielsweise master und das erste Commit Ihres Zweiges als direkter Nachkomme des Master-Zweigs. Dies bedeutet, dass wir jetzt einen Schnellvorlauf durchführen können, um Änderungen von diesem Zweig zum Hauptzweig zu bringen.
Einige praktische Beispiele, die etwas mit der Entwicklung im großen Maßstab zu tun haben, bei der Gerrit für die Überprüfung und Bereitstellung der Integration verwendet wird.
Ich verschmelze, wenn ich meinen Feature-Zweig zu einem neuen Remote-Master hochsteige. Dies führt zu minimalem Uplift-Aufwand und es ist einfach, die Entwicklung der Feature-Entwicklung in beispielsweise GitK zu verfolgen.
git fetch
git checkout Origin/my_feature
git merge Origin/master
git commit
git Push Origin HEAD:refs/for/my_feature
Ich verschmelze, wenn ich ein Lieferverpflichtung vorbereite.
git fetch
git checkout Origin/master
git merge --squash Origin/my_feature
git commit
git Push Origin HEAD:refs/for/master
Ich baue nach, wenn mein Bereitstellungs-Commit aus irgendeinem Grund die Integration fehlschlägt und ich ihn auf einen neuen Remote-Master aktualisieren muss.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase Origin/master
git Push Origin HEAD:refs/for/master
Schauen wir uns ein Beispiel an. Während der Arbeit an einem Zweig mit dem Namen login
, der auf dem Zweig master
basiert, hat eines Ihrer Teammitglieder einige Änderungen an master
vorgenommen. Sie benötigen diese Änderungen, um die Funktion login
in Ihrem Zweig zu beenden.
Abbildung 1. Die neuen Commits im Zweig
master
(E und F) werden benötigt, um die Arbeit im Zweig login
abzuschließen.
Das Zusammenführen des Zweigs master
in Ihren würde zu einem Zusammenführungs-Commit führen, das die Änderungen zwischen beiden Zweigen enthält und vorhanden ist, um anzuzeigen, wo eine Zusammenführung erfolgt aufgetreten.
Abbildung 2. Das Zusammenführen der beiden Zweige führt zu einem Merge-Commit.
Wir werden nicht wissen müssen, wann wir die master
in der login
-Niederlassung zusammengeführt haben. Stattdessen möchten wir vorgeben, dass alle Festschreibungen für den Zweig login
auf der Grundlage des neuen Zustands des Zweigs master
vorgenommen wurden.
Gits Rebase -Befehl spult die Commits in Ihrem aktuellen Zweig vorübergehend zurück, zieht die Commits aus dem anderen Zweig ein und wendet die zurückgespulten Commits wieder oben an. Durch Umschalten des Stroms Hiermit wird der Stromzweig auf den anderen Zweig gelegt.
Abbildung 3. Beim erneuten Starten werden die Festschreibungen aus dem Zweig login
über dem Zweig master
angewendet.
Die Quelle ist hier
Es wurde viele Male erklärt, was Rebase und welche Verschmelzung sind, aber wann was verwenden?
Wann verwenden Sie Rebase?
Als git rebase ändert sich die Historie. Daher sollten Sie es nicht verwenden, wenn eine andere Person in demselben Zweig arbeitet oder wenn Sie es geschoben haben. Wenn Sie jedoch eine Zweigstelle vor Ort haben, können Sie einen Rebase-Master zusammenführen, bevor Sie Ihre Zweigstelle wieder zu einem Master zusammenführen, um eine sauberere Historie zu erhalten. Nach dem Zusammenführen in den Master-Zweig ist es nicht sichtbar, dass Sie einen Zweig im Master-Zweig verwendet haben. Die Historie ist "sauberer", da Sie nicht automatisch "Zusammengeführt .." erstellt haben, aber immer noch den vollen Inhalt haben Geschichte in Ihrem Master-Zweig, ohne automatisch "zusammengeführt .." Commits erstellt zu haben. Stellen Sie jedoch sicher, dass Sie git merge feature-branch --ff-only
verwenden, um sicherzustellen, dass keine Konflikte beim Erstellen eines einzelnen Commits auftreten, wenn Sie Ihr Feature wieder mit dem Hauptelement zusammenführen.
Ein zweites Szenario wäre, wenn Sie sich von einem Zweig verzweigen und wissen möchten, was sich im Hauptzweig geändert hat. rebase liefert Ihnen die Informationen, da sie jedes Commit enthalten.
Wann wird die Zusammenführung verwendet?
Wenn Sie nicht die gesamte Historie eines Feature-Zweigs in Ihrem Master-Zweig benötigen oder möchten, oder wenn andere in demselben Zweig arbeiten/Sie haben ihn gepusht. Wenn Sie immer noch die Historie haben möchten, fügen Sie einfach den Master mit dem Feature-Zweig zusammen, bevor Sie den Feature-Zweig mit dem Master zusammenführen. Dies führt zu einer schnellen Zusammenführung, bei der sich der Verlauf des Feature-Zweigs in Ihrem Master befindet (einschließlich der Merge-Commit-Funktion, die sich in Ihrem Feature-Zweig befand, da Sie den Master mit ihm zusammengeführt haben).