it-swarm.com.de

Warum bevorzugen so viele Projekte "Git Rebase" gegenüber "Git Merge"?

Einer der Vorteile der Verwendung eines DVCS ist der Workflow edit-commit-merge (gegenüber edit-merge-commit oft von einem CVCS erzwungen). Wenn jede einzelne Änderung unabhängig von Zusammenführungen im Repository aufgezeichnet wird, wird sichergestellt, dass DAG den tatsächlichen Stammbaum des Projekts genau widerspiegelt.

Warum reden so viele Websites darüber, "Merge Commits vermeiden zu wollen"? Erschwert das Zusammenführen vor dem Festschreiben oder das erneute Basieren nach dem Zusammenführen nicht das Isolieren von Regressionen, das Zurücksetzen früherer Änderungen usw.?

Klarstellung: Das Standardverhalten für ein DVCS ist , um eine Zusammenführung zu erstellen begeht. Warum sprechen so viele Orte von dem Wunsch, eine lineare Entwicklungsgeschichte zu sehen, die diese Zusammenführungsverpflichtungen verbirgt?

71
Jace Browning

Die Benutzer möchten Zusammenführungs-Commits vermeiden, da dies das Protokoll schöner macht. Ernsthaft. Es sieht aus wie die zentralisierten Protokolle, mit denen sie aufgewachsen sind, und lokal können sie ihre gesamte Entwicklung in einem einzigen Zweig durchführen. Abgesehen von dieser Ästhetik gibt es keine Vorteile und einige Nachteile zusätzlich zu den von Ihnen erwähnten, wie z. B. die Konfliktanfälligkeit, direkt von einem Kollegen zu ziehen, ohne den "zentralen" Server zu durchlaufen.

66
Karl Bielefeldt

In zwei Worten: git bisect

Mit einem linearen Verlauf können Sie die tatsächliche Ursache eines Fehlers ermitteln.


def bar(arg=None):
    pass

def foo():
    bar()

Zweig 1 führt einige Umgestaltungen durch, sodass arg nicht mehr gültig ist:

def bar():
    pass

def foo():
    bar()

Zweig 2 verfügt über eine neue Funktion, die arg verwenden muss:

def bar(arg=None):
    pass

def foo():
    bar(arg=1)

Es wird keine Zusammenführungskonflikte geben, es wurde jedoch ein Fehler eingeführt. Glücklicherweise wird dieser eine beim Kompilierungsschritt 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 ein oder zwei Wochen lang nicht gefunden. An diesem Punkt, git bisect zur Rettung!

Oh Mist. Das sieht es:

(master: green)
|             \_________________________
|                \                      \
(master: green)  (branch 1: green)     (branch 2: green)
|                 |                     |
|                 |                     |
(master/merge commit: green)            |
|                         ______________/
|                        /
(master/merge commit: red)
|
...days pass...
|
(master: red)

Also, wenn wir git bisect Um das Commit zu finden, das den Build beschädigt hat, wird ein Merge-Commit ermittelt. Nun, das hilft ein wenig, aber es zeigt im Wesentlichen auf ein Paket von Commits, nicht auf ein einziges. Alle Vorfahren sind grün. Auf der anderen Seite erhalten Sie beim Umbasieren eine lineare Historie:

(master: green)
|
(master: green)
|
(all branch 1 commits: green)
|
(some branch 2 commits: green)
|
(branch 2 commit: red)
|
(remaining branch 2 commits: red)
|
...days pass...
|
(master: still red)

Jetzt, git bisect wird auf das genaue Feature-Commit verweisen, das den Build beschädigt hat. Im Idealfall wird in der Festschreibungsnachricht erläutert, was gut genug war, um einen weiteren Refactor durchzuführen und den Fehler sofort zu beheben.

Der Effekt wird nur in großen Projekten verstärkt, wenn die Betreuer nicht den gesamten Code geschrieben haben, sodass sie sich nicht unbedingt daran erinnern, warum ein bestimmtes Commit durchgeführt wurde/wofür jeder Zweig gedacht war. Das genaue Festschreiben des Commits (und das anschließende Überprüfen der Commits) ist daher eine große Hilfe.


Trotzdem bevorzuge ich (derzeit) immer noch das Zusammenführen. Wenn Sie auf einen Release-Zweig zurückgreifen, erhalten Sie Ihren linearen Verlauf zur Verwendung mit git bisect, während die wahre Geschichte für die tägliche Arbeit beibehalten wird.

48
Izkata

Kurz gesagt, denn das Zusammenführen ist oft ein weiterer Ort, an dem etwas schief gehen kann, und es muss nur einmal schief gehen, damit die Leute große Angst haben, wieder damit umzugehen (einmal zweimal schüchtern gebissen, wenn Sie so wollen).

Nehmen wir also an, wir arbeiten an einem neuen Kontoverwaltungsbildschirm, 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 neuen Konten. Da wir beide mit Konten zu tun haben, haben wir mit sehr ähnlichem Code gearbeitet - vielleicht mussten wir sogar dieselben Codeteile anpassen.

Derzeit haben wir zwei verschiedene, aber voll funktionsfähige Softwareversionen. Wir haben beide ein Commit für unsere Änderungen durchgeführt, wir haben unseren Code pflichtbewusst getestet und unabhängig davon sind wir sehr zuversichtlich, dass wir einen großartigen Job gemacht haben. Was jetzt?

Nun, es ist Zeit zu verschmelzen, aber ... Mist, was passiert jetzt? Wir könnten sehr gut von zwei funktionierenden Software-Sets zu einer einheitlichen, schrecklich kaputten neuen Buggy-Software wechseln, 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 intelligent und es gab einen Konflikt und bestand darauf, dass wir ihr eine Anleitung geben. Mist, ich setze mich dazu und sehe, dass Sie einen komplexen Code hinzugefügt haben, den ich nicht sofort verstehe. Ich denke, es steht im Widerspruch zu 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 zu setzen, eine ordnungsgemäße Zusammenführung durchzuführen und möglicherweise das ganze verdammte Ding erneut zu testen, um sicherzustellen, dass wir es nicht kaputt gemacht haben.

In der Zwischenzeit schreiben 8 andere Leute 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, und Mann, es scheint sicher ein guter Zeitpunkt zu sein, eine Pause einzulegen, und vielleicht auch Sie sind für den Nachmittag weg oder stecken in einer Besprechung oder was auch immer. Vielleicht sollte ich einfach Urlaub machen. Oder Karriere wechseln.

Um diesem Albtraum zu entkommen, haben einige Menschen große Angst vor Engagement (was ist sonst noch neu, oder?). In solchen Szenarien sind wir natürlich risikoscheu - es sei denn, wir glauben, wir saugen und werden es trotzdem vermasseln. In diesem Fall beginnen die Leute mit rücksichtsloser Hingabe zu handeln. seufz

Hier bitteschön. Ja, moderne Systeme sind so konzipiert, dass sie diesen Schmerz lindern, und sie sollen in der Lage sein, sich leicht zurückzuziehen und neu zu gründen und zu entwerten und freizugeben und zu hängen und all das.

Aber es ist alles mehr Arbeit, und wir wollen nur den Knopf in 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 aussagekräftig, aber elegant mit einer Zusammenführung umgehen nur zählt nicht.

Programmierer müssen in der Regel ein gutes Arbeitsgedächtnis entwickeln und dann die Tendenz haben, all diese Junk- und Variablennamen und das Scoping sofort zu vergessen, sobald sie das Problem gelöst haben, und einen Zusammenführungskonflikt zu behandeln (oder schlimmer noch, a falsch gehandhabtes Zusammenführen) ist eine Einladung, an Ihre Sterblichkeit erinnert zu werden.

16
BrianH

Das erneute Basieren bietet einen sich bewegenden Verzweigungspunkt, der das Zurückschieben von Änderungen auf die Basislinie vereinfacht. Auf diese Weise können Sie einen Zweig mit langer Laufzeit so behandeln, als wäre es eine lokale Änderung. Ohne erneutes Basieren akkumulieren Zweige Änderungen von der Basislinie, die in den Änderungen enthalten sind, die wieder zur Basislinie zusammengeführt werden.

Durch das Zusammenführen bleibt Ihre Grundlinie am ursprünglichen Verzweigungspunkt. Wenn Sie Änderungen von der Linie, von der Sie abgezweigt haben, im Wert von einigen Wochen zusammenführen, haben Sie jetzt viele Änderungen von Ihrem Verzweigungspunkt, von denen sich viele in Ihrer Grundlinie befinden. Dies macht es schwierig, Ihre Änderungen in Ihrer Branche zu identifizieren. Das Zurückschieben von Änderungen auf die Basislinie kann zu Konflikten führen, die nicht mit Ihren Änderungen zusammenhängen. Bei Konflikten ist es möglich, inkonsistente Änderungen zu pushen. Laufende Zusammenführungen sind aufwändig zu verwalten, und es ist relativ einfach, Änderungen zu verlieren.

Rebase verschiebt Ihren Verzweigungspunkt auf die neueste Version Ihrer Baseline. Alle Konflikte, auf die Sie stoßen, betreffen nur Ihre Änderung (en). Das Verschieben von Änderungen ist viel einfacher. Konflikte werden in der lokalen Niederlassung durch eine zusätzliche Rebase behandelt. Bei widersprüchlichen Pushs muss der letzte, der seine Änderung pusht, das Problem mit seiner Änderung beheben.

5
BillThor

Die automatisierten Tools stellen immer besser sicher, dass der zusammengeführte Code kompiliert und ausgeführt wird, wodurch syntaktische Konflikte vermieden werden. Sie können jedoch nicht garantieren, dass logische Konflikte eingeführt werden durch Zusammenführungen. Eine "erfolgreiche" Zusammenführung gibt Ihnen ein Gefühl von falschem Vertrauen, wenn sie in Wirklichkeit nichts garantiert und Sie alle Ihre Tests wiederholen müssen.

Das eigentliche Problem beim Verzweigen und Zusammenführen ist, wie ich es sehe, dass es die sprichwörtliche Dose die Straße hinunter tritt. Sie können eine Woche lang sagen: "Ich werde nur in meiner eigenen kleinen Welt arbeiten" und sich mit allen später auftretenden Problemen befassen. Das Beheben von Fehlern ist jedoch immer schneller/billiger, wenn sie frisch sind. Wenn alle Codezweige zusammengeführt werden, vergessen Sie möglicherweise bereits einige Nuancen der durchgeführten Aktionen.

Nehmen Sie die beiden oben genannten Probleme zusammen, und Sie befinden sich möglicherweise in einer Situation, in der es einfacher und einfacher ist, alle Mitarbeiter aus demselben Stamm herausarbeiten zu lassen und Konflikte kontinuierlich zu lösen, selbst wenn sie die aktive Entwicklung etwas verlangsamen.

4
MrFox

Ein weiterer relevanter Punkt ist folgender: Mit dem erneuten Basieren kann ich problemlos ein Feature in meinem Release-Zweig auswählen oder zurücksetzen.

0
Bruno Schäpper

Drei Dinge wurden in keiner der Antworten gesagt:

  • Innerhalb eines Zweigs unterscheiden:

    • Das Unterscheiden zwischen einem beliebigen Commit-Paar in einem Zweig wird extrem schwierig, wenn Merge-Commits vorhanden sind.
  • Zusammenführen von jeweils einem Element:

    • Wenn Sie den Unterschied zwischen zwei Zweigen beheben, erfolgt eine Zusammenführung normalerweise auf einmal, und alle Zusammenführungskonflikte, die Sie ausführen müssen, ohne den Kontext, für den ein bestimmtes Commit für den Konflikt verantwortlich war. Wenn Sie die Basis neu erstellen, wird die Basis an dem Punkt gestoppt, an dem der Konflikt aufgetreten ist, und Sie können ihn in diesem Kontext lösen.
  • Aufräumen vor dem Push:

    • Wenn Sie einen Fehler begangen haben, den Sie später beheben müssen, können Sie Commits kombinieren/teilen/ändern/verschieben, wenn Sie die interaktive Rebase nicht gedrückt haben. Während Sie dies immer noch tun können, wenn Sie zusammengeführt haben, wird es sehr schwierig, wenn Sie eine Zusammenführungsgrenze kombinieren/teilen/ändern/verschieben möchten.
0
Catskul