Einer der Vorteile der Verwendung eines DVCS ist der Workflow zum Bearbeiten, Festschreiben und Zusammenführen (gegenüber dem Bearbeiten, Zusammenführen und Festschreiben , der häufig von einem CVCS erzwungen wird). Indem jede einzelne Änderung unabhängig von Zusammenführungen im Repository aufgezeichnet wird, wird sichergestellt, dass die DAG den tatsächlichen Stammbaum des Projekts genau wiedergibt.
Warum reden so viele Websites davon, "Merge Commits vermeiden" zu wollen? Erschwert das Zusammenführen von Pre-Commit- oder Re-Basing-Vorgängen nach dem Zusammenführen nicht das Isolieren von Regressionen, das Zurücksetzen früherer Änderungen usw.?
Klarstellungspunkt: Das Standardverhalten für ein DVCS ist das Erstellen von Merge-Commits. Warum sprechen so viele Orte von dem Wunsch, eine lineare Entwicklungsgeschichte zu sehen, in der diese Merge-Commits ausgeblendet sind?
quelle
git pull
)? Ich kann sehen, warum das problematisch sein könnte, aber meine Frage bezieht sich auf alle Merge-Commits.git pull --rebase == svn up
(Gleichheit, nicht Gleichheit)Antworten:
Leute möchten Merge-Commits vermeiden, da dies das Protokoll schöner macht. Ernsthaft. Es sieht aus wie die zentralen Protokolle, mit denen sie aufgewachsen sind, und vor Ort können sie ihre gesamte Entwicklung in einer einzigen Filiale durchführen. Abgesehen von dieser Ästhetik gibt es keine Vorteile und zusätzlich zu den von Ihnen erwähnten auch einige Nachteile, z. B. dass es konfliktträchtig ist, direkt von einem Kollegen zu ziehen, ohne den "zentralen" Server zu durchlaufen.
quelle
In zwei Worten:
git bisect
Mit einem linearen Verlauf können Sie die tatsächliche Fehlerquelle genau bestimmen.
Ein Beispiel. Dies ist unser Anfangscode:
Zweig 1 führt einige Umgestaltungen durch,
arg
die nicht mehr gültig sind:Branch 2 hat eine neue Funktion, die verwendet werden muss
arg
:Es wird keine Zusammenführungskonflikte geben, es wurde jedoch ein Fehler behoben. Glücklicherweise wird dieser eine beim Kompilieren erwischt, aber wir haben nicht immer so viel Glück. Wenn sich der Fehler als unerwartetes Verhalten und nicht als Kompilierungsfehler manifestiert, wird er möglicherweise erst nach ein oder zwei Wochen gefunden. An diesem Punkt
git bisect
zur Rettung!Oh Mist. Das sieht es so:
Wenn wir also losschicken
git bisect
, um das Commit zu finden, das den Build unterbrochen hat, wird es ein Merge-Commit lokalisieren. Nun, das hilft ein wenig, aber es zeigt im Wesentlichen auf ein Paket von Commits, nicht auf ein einzelnes. Alle Vorfahren sind grün. Auf der anderen Seite erhalten Sie beim Neu-Basieren eine lineare Historie:Nun
git bisect
wird auf das genaue Feature-Commit hingewiesen, das den Build unterbrochen hat. Im Idealfall wird in der Festschreibungsmeldung erläutert, was gut genug ist, um einen weiteren Refaktor durchzuführen und den Fehler sofort zu beheben.Der Effekt wird nur in großen Projekten verstärkt, in denen die Betreuer nicht den gesamten Code geschrieben haben, sodass sie sich nicht unbedingt daran erinnern, warum ein bestimmtes Commit ausgeführt wurde bzw. wofür die einzelnen Zweige bestimmt waren. Das Festlegen des genauen Commits (und das anschließende Überprüfen der Commits in der Umgebung) ist daher eine große Hilfe.
Trotzdem bevorzuge ich (derzeit) das Zusammenführen. Durch erneutes Aufrufen eines Release-Zweigs können Sie Ihren linearen Verlauf für die Verwendung mit verwenden
git bisect
, während der wahre Verlauf für die tägliche Arbeit beibehalten wird.quelle
gitk --all
ist es äußerst nützlich, den Fluss von Commits über Filialen hinweg zu sehen (zumal ich in der Regel zu einem bestimmten Zeitpunkt dreistufige Filialen habe und abhängig von meiner Stimmung bei jeden Tag zwischen diesen umschalte) die Zeit).bisect
Ergebnis. Es ist einfach genug, die einzelnen Commits mit einemblame
oder einem anderen zu finden,bisect
wenn Sie tiefer graben möchten. Bei einem linearen Verlauf erfolgt die Zusammenführung außerhalb des Buchs, sodass Sie nicht mehr feststellen können, dass eine fehlerhafte Zusammenführung das Problem war. Es sieht aus wie ein Idiot, der ein Argument verwendet, das nicht existiert, insbesondere wenn das Argument zuvor um mehrere Commits entfernt wurde. Der Versuch, herauszufinden, warum er das tun würde, ist viel schwieriger, wenn Sie die Geschichte zerstören.Kurz gesagt, weil das Verschmelzen oft ein anderer Ort ist, an dem etwas schief gehen kann, und es nur einmal schief gehen muss, damit die Menschen Angst davor haben, es erneut zu tun (wenn Sie so wollen, einmal zweimal schüchtern gebissen).
Nehmen wir also an, wir arbeiten an einem neuen Bildschirm für die Kontoverwaltung, und es stellt sich heraus, dass im Workflow für neue Konten ein Fehler entdeckt wurde. OK, wir gehen zwei getrennte Wege - Sie beenden die Kontoverwaltung und ich behebe den Fehler mit "Neue Konten". Da wir uns beide mit Konten befassen, haben wir mit sehr ähnlichem Code gearbeitet - vielleicht mussten wir sogar dieselben Codeteile anpassen.
Momentan haben wir zwei verschiedene, aber voll funktionsfähige Versionen von Software. Wir haben beide einen Commit für unsere Änderungen ausgeführt, wir haben unseren Code beide pflichtbewusst getestet und sind unabhängig davon sehr zuversichtlich, dass wir eine großartige Arbeit geleistet haben. Was jetzt?
Nun, es ist Zeit zu fusionieren, aber ... Mist, was passiert jetzt? Wir könnten sehr gut von zwei funktionierenden Software-Sätzen zu einem vereinheitlichten, schrecklich kaputten Teil einer neu fehlerhaften Software übergehen, bei der Ihre Kontoverwaltung nicht funktioniert und neue Konten kaputt sind und ich nicht einmal weiß, ob der alte Fehler noch vorhanden ist .
Vielleicht war die Software schlau und es gab einen Konflikt und bestand darauf, dass wir sie anleiten. Scheiße, ich setze mich hin und sehe, dass Sie einen komplexen Code hinzugefügt haben, den ich nicht sofort verstehe. Ich denke, es widerspricht den Änderungen, die ich vorgenommen habe ... Ich frage Sie, und wenn Sie eine Minute Zeit haben, überprüfen Sie, und Sie sehen meinen Code, den Sie nicht verstehen. Einer oder beide von uns müssen sich die Zeit nehmen, sich hinzusetzen, eine ordnungsgemäße Zusammenführung vorzunehmen und möglicherweise die ganze Sache noch einmal zu testen, um sicherzustellen, dass wir sie nicht kaputt gemacht haben.
In der Zwischenzeit schreiben 8 andere Typen Code wie die Sadisten, die sie sind. Ich habe ein paar kleine Fehlerbehebungen vorgenommen und sie eingereicht, bevor ich wusste, dass wir einen Zusammenführungskonflikt hatten sind für den Nachmittag weg oder stecken in einer Besprechung oder was auch immer. Vielleicht sollte ich einfach mal Urlaub machen. Oder Karrieren wechseln.
Um diesem Albtraum zu entkommen, haben einige Menschen große Angst vor Engagement (was gibt es sonst noch Neues?). In solchen Szenarien sind wir natürlich risikoscheu - es sei denn, wir glauben, dass wir scheißen und es trotzdem vermasseln werden. In diesem Fall handeln die Leute mit rücksichtsloser Hingabe. Seufzer
Hier bitteschön. Ja, moderne Systeme wurden entwickelt, um diesen Schmerz zu lindern, und es sollte möglich sein, einfach zurückzutreten und zu rebasieren und zu debasieren und freebase und hanglide und so weiter.
Aber es ist viel mehr Arbeit, und wir möchten nur den Knopf auf der Mikrowelle drücken und ein 4-Gänge-Menü zubereiten, bevor wir Zeit haben, eine Gabel zu finden, und alles fühlt sich so unerfüllt an - Code ist Arbeit, es ist produktiv, es ist Sinnvolles, aber anmutiges Zusammenführen zählt einfach nicht.
Programmierer müssen in der Regel ein großartiges Arbeitsgedächtnis entwickeln und dann die Tendenz haben, alle Junk - und Variablennamen und das Scoping sofort zu vergessen, sobald sie das Problem gelöst haben, und einen Zusammenführungskonflikt (oder schlimmer noch: a falsch gehandhabte Zusammenführung) ist eine Aufforderung, an Ihre Sterblichkeit erinnert zu werden.
quelle
Durch das erneute Reduzieren wird ein verschiebbarer Verzweigungspunkt bereitgestellt, der das Zurückschieben von Änderungen an die Basislinie vereinfacht. Auf diese Weise können Sie einen Zweig mit langer Laufzeit so behandeln, als wäre es eine lokale Änderung. Bei Verzweigungen werden Änderungen von der Basislinie akkumuliert, die in den Änderungen enthalten sind, die wieder zur Basislinie zusammengeführt werden.
Beim Zusammenführen verbleibt Ihre Basislinie am ursprünglichen Verzweigungspunkt. Wenn Sie Änderungen aus der Linie, von der Sie abgezweigt sind, für ein paar Wochen zusammenführen, haben Sie jetzt viele Änderungen von Ihrem Verzweigungspunkt aus, von denen sich viele in Ihrer Grundlinie befinden. Dies macht es schwierig, Ihre Änderungen in Ihrer Branche zu identifizieren. Das Zurückschieben von Änderungen an die Grundlinie kann zu Konflikten führen, die nicht mit Ihren Änderungen zusammenhängen. Im Falle von Konflikten ist es möglich, inkonsistente Änderungen zu pushen. Laufende Zusammenführungen erfordern viel Aufwand und es ist relativ einfach, Änderungen zu verlieren.
Durch erneutes Starten wird der Verzweigungspunkt auf die neueste Version auf Ihrer Basislinie verschoben. Alle Konflikte, auf die Sie stoßen, betreffen nur Ihre Änderungen. Das Verschieben von Änderungen ist viel einfacher. Konflikte werden in der lokalen Niederlassung durch eine zusätzliche Rebase behandelt. Im Falle widersprüchlicher Pushs muss das Problem mit der Änderung behoben werden, wenn der letzte Push die Änderung vornimmt.
quelle
Die automatisierten Tools können immer besser sicherstellen, dass der Zusammenführungscode kompiliert und ausgeführt wird, wodurch syntaktische Konflikte vermieden werden. Sie können jedoch nicht die Abwesenheit logischer Konflikte garantieren, die durch Zusammenführungen entstehen können. Eine „erfolgreiche“ Zusammenführung gibt Ihnen das Gefühl eines falschen Vertrauens, wenn sie in Wirklichkeit nichts garantiert und Sie alle Ihre Tests wiederholen müssen.
Das eigentliche Problem beim Verzweigen und Zusammenführen ist meines Erachtens, dass es die sprichwörtliche Dose die Straße hinunterwirft. Sie können eine Woche lang "Ich arbeite nur in meiner eigenen kleinen Welt" sagen und alle Probleme behandeln, die später auftauchen. Aber das Beheben von Fehlern ist immer schneller / billiger, wenn sie frisch sind. Wenn alle Code-Zweige zusammengeführt werden, vergessen Sie möglicherweise bereits einige Nuancen der durchgeführten Aktionen.
Nehmen Sie die beiden oben genannten Probleme zusammen, und Sie könnten sich in einer Situation befinden, in der es einfacher und einfacher ist, dass alle am selben Stamm arbeiten und Konflikte fortlaufend lösen, selbst wenn sie die aktive Entwicklung etwas verlangsamen.
quelle
Ein weiterer relevanter Punkt ist folgender: Mit dem Rebasing kann ich problemlos ein Feature in meinem Release-Zweig auswählen oder zurücksetzen.
quelle
git cherry-pick -x <commit>
, wenden wir ihn auf den Veröffentlichungszweig an. Oder wir möchten vielleicht etwas für die Veröffentlichung rückgängig machen, mitgit revert <commit>
. Wenn<commit>
es sich um eine Verschmelzung handelt, wird es haarig. Es ist möglich, soweit ich weiß, aber nicht einfach zu tun. Bei der Verwendung von Rebase ist jede "Zusammenführung" ein riesiger, aber regelmäßiger Commit, der leicht auswählbar und rückgängig zu machen ist.Drei Dinge wurden in keiner der Antworten gesagt:
Innerhalb eines Zweiges unterscheiden:
Jeweils ein Element zusammenführen:
Aufräumen vor dem Push:
quelle