it-swarm.com.de

Mein Büro möchte, dass unendliche Zweigstellen als Richtlinie zusammengeführt werden. Welche anderen Möglichkeiten haben wir?

Mein Büro versucht herauszufinden, wie wir mit Filialaufteilungen und -zusammenführungen umgehen, und wir sind auf ein großes Problem gestoßen.

Unser Problem sind langfristige Nebenzweige - die Art, bei der einige Leute an einem Nebenzweig arbeiten, der sich vom Master trennt, entwickeln wir für einige Monate, und wenn wir einen Meilenstein erreichen, synchronisieren wir die beiden.

Nun, IMHO, ist die natürliche Art, damit umzugehen, die Sidebranch in einem einzigen Commit zu zerquetschen. master schreitet weiter voran; wie es sollte - wir werfen nicht rückwirkend Monate paralleler Entwicklung in die Geschichte von master. Und wenn jemand eine bessere Lösung für die Geschichte der Sidebranch braucht, dann ist natürlich alles noch da - es ist einfach nicht in master, es ist in der Sidebranch.

Hier ist das Problem: Ich arbeite ausschließlich mit der Befehlszeile, aber der Rest meines Teams verwendet GUIS. Und ich habe festgestellt, dass das GUIS keine vernünftige Option zum Anzeigen des Verlaufs aus anderen Zweigen bietet. Wenn Sie also ein Squash-Commit erreichen und sagen "Diese Entwicklung wurde aus dem Zweig XYZ gequetscht", ist es ein großer Schmerz, zu sehen, was in XYZ enthalten ist. .

Bei SourceTree ist es, soweit ich es finden kann, ein großes Problem: Wenn Sie auf master sind und den Verlauf von master+devFeature Anzeigen möchten, müssen Sie entweder überprüfen master+devFeature Heraus (Berühren jeder einzelnen Datei, die anders ist), oder scrollen Sie durch ein Protokoll, in dem [~ # ~] alle [~ # ~] Zweige Ihres Repositorys angezeigt werden parallel, bis Sie den richtigen Ort finden. Und viel Glück beim Herausfinden, wo Sie dort sind.

Meine Teamkollegen möchten zu Recht nicht, dass die Entwicklungsgeschichte so unzugänglich ist. Sie wollen also, dass diese großen, langen Entwicklungszweige zusammengeführt werden, immer mit einem Merge-Commit. Sie wollen keinen Verlauf, auf den der Hauptzweig nicht sofort zugreifen kann.

Ich hasse diese Idee; es bedeutet ein endloses, nicht befahrbares Gewirr paralleler Entwicklungsgeschichte. Aber ich sehe nicht, welche Alternative wir haben. Und ich bin ziemlich verblüfft; Dies scheint fast alles zu blockieren, was ich über gutes Filialmanagement weiß, und es wird eine ständige Frustration für mich sein, wenn ich keine Lösung finde.

Haben wir hier eine andere Möglichkeit, als ständig Nebenzweige mit Merge-Commits zu Master zusammenzuführen? Oder gibt es einen Grund, warum die ständige Verwendung von Merge-Commits nicht so schlecht ist, wie ich befürchte?

120
Standback

Obwohl ich Git in der Kommandozeile benutze, muss ich Ihren Kollegen zustimmen. Es ist nicht sinnvoll, große Änderungen in einem einzigen Commit zusammenzufassen. Auf diese Weise verlieren Sie die Geschichte und machen sie nicht nur weniger sichtbar.

Der Punkt der Quellcodeverwaltung besteht darin, den Verlauf aller Änderungen zu verfolgen. Wann hat sich was geändert, warum? Zu diesem Zweck enthält jedes Commit Zeiger auf übergeordnete Commits, ein Diff und Metadaten wie eine Commit-Nachricht. Jedes Commit beschreibt den Status des Quellcodes und den vollständigen Verlauf aller Änderungen, die zu diesem Status geführt haben. Der Garbage Collector kann Commits löschen, die nicht erreichbar sind.

Aktionen wie erneutes Basieren, Kirschpflücken oder Quetschen löschen oder schreiben den Verlauf neu. Insbesondere verweisen die resultierenden Commits nicht mehr auf die ursprünglichen Commits. Bedenken Sie:

  • Sie quetschen einige Commits und stellen in der Commit-Nachricht fest, dass der Squashed-Verlauf im ursprünglichen Commit abcd123 verfügbar ist.
  • Du löschst[1] Alle Zweige oder Tags, die abcd123 enthalten, seit sie zusammengeführt wurden.
  • Sie lassen den Garbage Collector laufen.

[1]: Einige Git-Server ermöglichen den Schutz von Zweigen vor versehentlichem Löschen, aber ich bezweifle, dass Sie alle Ihre Feature-Zweige für die Ewigkeit behalten möchten.

Jetzt können Sie dieses Commit nicht mehr nachschlagen - es existiert einfach nicht.

Das Verweisen auf einen Filialnamen in einer Commit-Nachricht ist noch schlimmer, da Filialnamen für ein Repo lokal sind. Was ist master+devFeature in Ihrer lokalen Kasse könnte doodlediduh in meiner sein. Zweige verschieben nur Beschriftungen, die auf ein Festschreibungsobjekt verweisen.

Von allen Techniken zum Umschreiben des Verlaufs ist das erneute Basieren am harmlosesten, da es die vollständigen Festschreibungen mit dem gesamten Verlauf dupliziert und nur ein übergeordnetes Festschreiben ersetzt.

Dass die master -Historie die vollständige Historie aller Zweige enthält, die darin zusammengeführt wurden, ist eine gute Sache, denn das repräsentiert die Realität.[2] Wenn es eine parallele Entwicklung gab, sollte dies im Protokoll sichtbar sein.

[2]: Aus diesem Grund bevorzuge ich auch explizite Merge-Commits gegenüber der linearisierten, aber letztendlich gefälschten Historie, die sich aus der Neugründung ergibt.

In der Befehlszeile git log bemüht sich, den angezeigten Verlauf zu vereinfachen und alle angezeigten Commits relevant zu halten. Sie können die Vereinfachung des Verlaufs an Ihre Bedürfnisse anpassen. Sie könnten versucht sein, ein eigenes Git-Protokoll-Tool zu schreiben, das das Commit-Diagramm durchläuft, aber es ist im Allgemeinen unmöglich zu antworten, ob dieses Commit ursprünglich für diesen oder jenen Zweig festgeschrieben wurde. Das erste übergeordnete Element eines Zusammenführungs-Commits ist das vorherige HEAD, d. H. Das Commit in dem Zweig, in den Sie zusammenführen. Dies setzt jedoch voraus, dass Sie keine umgekehrte Zusammenführung vom Master in den Feature-Zweig und dann einen schnellen Vorlauf des Masters zur Zusammenführung durchgeführt haben.

Die beste Lösung für langfristige Zweige, auf die ich gestoßen bin, besteht darin, Zweige zu verhindern, die erst nach ein paar Monaten zusammengeführt werden. Das Zusammenführen ist am einfachsten, wenn die Änderungen neu und klein sind. Im Idealfall werden Sie mindestens einmal pro Woche zusammengeführt. Die kontinuierliche Integration (wie bei der extremen Programmierung, nicht wie bei „Richten wir einen Jenkins-Server ein“) schlägt sogar mehrere Zusammenführungen pro Tag vor, d. H. Keine separaten Feature-Zweige zu verwalten, sondern einen Entwicklungszweig als Team zu teilen. Das Zusammenführen vor der Qualitätssicherung eines Features erfordert, dass das Feature hinter einem Feature-Flag versteckt ist.

Im Gegenzug ermöglicht eine häufige Integration, potenzielle Probleme viel früher zu erkennen und eine konsistente Architektur beizubehalten: Weitreichende Änderungen sind möglich, da diese Änderungen schnell in allen Branchen enthalten sind. Wenn eine Änderung einen Code beschädigt, wird nur ein paar Tage Arbeit unterbrochen, nicht ein paar Monate.

Das Umschreiben des Verlaufs kann für wirklich große Projekte sinnvoll sein, wenn mehrere Millionen Codezeilen und Hunderte oder Tausende aktiver Entwickler vorhanden sind. Es ist fraglich, warum ein so großes Projekt ein einzelnes Git-Repo sein müsste, anstatt in separate Bibliotheken unterteilt zu werden. In dieser Größenordnung ist es jedoch bequemer, wenn das zentrale Repo nur „Releases“ der einzelnen Komponenten enthält. Z.B. Der Linux-Kernel verwendet Squashing, um den Hauptverlauf überschaubar zu halten. Bei einigen Open Source-Projekten müssen Patches per E-Mail gesendet werden, anstatt auf Git-Ebene zusammengeführt zu werden.

245
amon

Ich mag Amons Antwort , aber ich hatte das Gefühl, dass ein kleiner Teil viel mehr Nachdruck benötigt: Sie können den Verlauf beim Anzeigen von Protokollen leicht vereinfachen, um Ihren Anforderungen gerecht zu werden, andere können ihn jedoch nicht hinzufügen Verlauf beim Anzeigen von Protokollen, um deren Anforderungen zu erfüllen. Aus diesem Grund ist es vorzuziehen, den Verlauf so beizubehalten, wie er aufgetreten ist.

Hier ist ein Beispiel aus einem unserer Repositories. Wir verwenden ein Pull-Request-Modell, daher sieht die Funktion every Wie Ihre lang laufenden Zweige in der Geschichte aus, obwohl sie normalerweise nur eine Woche oder weniger laufen. Einzelne Entwickler entscheiden sich manchmal dafür, ihren Verlauf vor dem Zusammenführen zu quetschen, aber wir arbeiten häufig an Funktionen, sodass dies relativ ungewöhnlich ist. Hier sind die wichtigsten Commits in gitk, der mit git gebündelten GUI:

(standard gitk view

Ja, ein bisschen verwickelt, aber wir mögen es auch, weil wir genau sehen können, wer zu welcher Zeit welche Änderungen hatte. Es spiegelt genau unsere Entwicklungsgeschichte wider. Wenn wir eine übergeordnete Ansicht sehen möchten, bei der jeweils eine Pull-Anforderung zusammengeführt wird, können wir uns die folgende Ansicht ansehen, die dem Befehl git log --first-parent Entspricht:

(gitk view with --first-parent

git log Bietet viele weitere Optionen, mit denen Sie genau die gewünschten Ansichten erhalten. gitk kann ein beliebiges git log - Argument verwenden, um eine grafische Ansicht zu erstellen. Ich bin sicher, dass andere GUIs ähnliche Funktionen haben. Lesen Sie die Dokumente und lernen Sie, sie richtig zu verwenden, anstatt Ihre bevorzugte git log - Ansicht für alle zum Zeitpunkt der Zusammenführung durchzusetzen.

110
Karl Bielefeldt

Unser Problem sind langfristige Nebenzweige - die Art, bei der einige Leute an einem Nebenzweig arbeiten, der sich vom Master trennt, entwickeln wir für einige Monate, und wenn wir einen Meilenstein erreichen, synchronisieren wir die beiden.

Mein erster Gedanke ist - mach das nicht einmal, es sei denn, es ist absolut notwendig. Ihre Zusammenschlüsse müssen manchmal schwierig sein. Halten Sie Filialen unabhängig und so kurzlebig wie möglich. Dies ist ein Zeichen dafür, dass Sie Ihre Storys in kleinere Implementierungsblöcke aufteilen müssen.

In dem Fall, dass Sie dies tun müssen, ist es möglich, in git mit der Option --no-ff zusammenzuführen, so dass die Historien in ihrem eigenen Zweig getrennt bleiben. Die Commits werden weiterhin im zusammengeführten Verlauf angezeigt, können jedoch auch separat im Feature-Zweig angezeigt werden, sodass zumindest festgestellt werden kann, zu welcher Entwicklungslinie sie gehörten.

Ich muss zugeben, als ich anfing, git zum ersten Mal zu verwenden, fand ich es etwas seltsam, dass die Branch Commits nach dem Zusammenführen in derselben Historie wie der Hauptzweig erschienen. Es war ein wenig beunruhigend, weil es nicht so schien, als gehörten diese Verpflichtungen in diese Geschichte. In der Praxis ist dies jedoch überhaupt nicht schmerzhaft, wenn man bedenkt, dass der Integrationszweig genau das ist - sein ganzes Zweck besteht darin, die Feature-Zweige zu kombinieren. In unserem Team quetschen wir nicht und führen häufig Zusammenführungs-Commits durch. Wir verwenden ständig --no-ff, um sicherzustellen, dass der genaue Verlauf eines Features leicht zu sehen ist, falls wir ihn untersuchen möchten.

34
Brad Thomas

Wenn Sie einen langfristigen Sidebranch zerquetschen, verlieren Sie viele Informationen.

Was ich tun würde, ist versuchen Sie, den Master in die langfristige Sidebranch umzuwandeln, bevor Sie die Sidebranch in den Master zusammenführen. Auf diese Weise behalten Sie jedes Commit im Master bei und machen den Commit-Verlauf linear und verständlicher.

Wenn ich das nicht bei jedem Commit einfach machen könnte, würde ich es nicht linear lassen, um den Entwicklungskontext klar zu halten. Wenn ich während der Wiederherstellung des Masters in die Sidebranche eine problematische Verschmelzung habe, bedeutet dies meiner Meinung nach, dass die Nichtlinearität eine reale Bedeutung hatte. Das heißt, es wird einfacher zu verstehen sein, was passiert ist, wenn ich mich in die Geschichte vertiefen muss. Ich habe auch den unmittelbaren Vorteil, dass ich keine Rebase durchführen muss.

10

Lassen Sie mich Ihre Punkte direkt und klar beantworten :

Unser Problem sind langfristige Nebenzweige - die Art, bei der einige Leute an einem Nebenzweig arbeiten, der sich vom Master trennt, entwickeln wir für einige Monate, und wenn wir einen Meilenstein erreichen, synchronisieren wir die beiden.

Normalerweise möchten Sie Ihre Filialen nicht monatelang nicht synchronisieren.

Ihr Feature-Zweig hat sich abhängig von Ihrem Workflow von etwas verzweigt. Nennen wir es der Einfachheit halber einfach master. Wann immer Sie sich zum Master verpflichten, können und sollten Sie git checkout long_running_feature ; git rebase master. Dies bedeutet, dass Ihre Filialen von Natur aus immer synchron sind.

git rebase Ist auch hier das Richtige. Es ist kein Hack oder etwas Seltsames oder Gefährliches, sondern völlig natürlich. Sie verlieren eine Information, nämlich den "Geburtstag" des Feature-Zweigs, aber das war's. Wenn jemand dies für wichtig hält, kann es bereitgestellt werden, indem es an einem anderen Ort gespeichert wird (in Ihrem Ticketsystem oder, wenn der Bedarf groß ist, in einem git tag ...).

Nun, IMHO, ist die natürliche Art, damit umzugehen, die Sidebranch in einem einzigen Commit zu zerquetschen.

Nein, das wollen Sie absolut nicht, Sie wollen ein Merge-Commit. Ein Merge-Commit ist auch ein "Single-Commit". Es werden nicht alle einzelnen Branch Commits "in" Master eingefügt. Es handelt sich um ein einzelnes Commit mit zwei übergeordneten Elementen - dem master -Kopf und dem Zweigkopf zum Zeitpunkt der Zusammenführung.

Stellen Sie sicher, dass Sie die Option --no-ff Angeben. Das Zusammenführen ohne --no-ff sollte in Ihrem Szenario strengstens verboten sein. Leider ist --no-ff Nicht die Standardeinstellung. Aber ich glaube, es gibt eine Option, die Sie festlegen können, die es so macht. Siehe git help merge Für die Funktionen von --no-ff (Kurz gesagt: Es aktiviert das Verhalten, das ich im vorherigen Absatz beschrieben habe). Es ist von entscheidender Bedeutung.

wir werfen nicht monatelang parallele Entwicklungen rückwirkend in die Geschichte des Meisters.

Absolut nicht - Sie werfen niemals etwas "in die Geschichte" eines Zweigs, insbesondere nicht mit einem Merge-Commit.

Und wenn jemand eine bessere Lösung für die Geschichte der Sidebranch braucht, dann ist natürlich alles noch da - es ist einfach nicht im Master, es ist in der Sidebranch.

Mit einem Merge-Commit ist es immer noch da. Nicht im Meister, sondern im Nebenzweig, deutlich sichtbar als einer der Elternteile des Zusammenschlusses, und für die Ewigkeit aufbewahrt, wie es sein sollte.

Sehen Sie, was ich getan habe? Alle Dinge, die Sie für Ihr Squash-Commit beschreiben, sind genau dort mit dem Merge-Commit --no-ff.

Hier ist das Problem: Ich arbeite ausschließlich mit der Befehlszeile, aber der Rest meines Teams verwendet GUIS.

(Nebenbemerkung: Ich arbeite fast ausschließlich auch mit der Befehlszeile (nun, das ist eine Lüge, ich verwende normalerweise Emacs Magit, aber das ist eine andere Geschichte - wenn ich mit meinem individuellen Emacs-Setup nicht an einem geeigneten Ort bin, bevorzuge ich den Befehl Linie auch). Aber bitte tun Sie sich selbst einen Gefallen und versuchen Sie es mindestens einmal mit git gui. Es ist so viel effizienter, um Linien, Hunks usw. zum Hinzufügen/Rückgängigmachen von Adds auszuwählen.)

Und ich habe festgestellt, dass GUIS keine vernünftige Option zum Anzeigen des Verlaufs anderer Branchen bietet.

Das liegt daran, dass das, was Sie versuchen, völlig gegen den Geist von git ist. git baut aus dem Kern auf einem "gerichteten azyklischen Graphen" auf, was bedeutet, dass sich viele Informationen in der Eltern-Kind-Beziehung von Commits befinden. Und für Zusammenschlüsse bedeutet dies, dass echte Zusammenschlüsse mit zwei Eltern und einem Kind durchgeführt werden. Die GUIs Ihrer Kollegen sind in Ordnung, sobald Sie no-ff Merge-Commits verwenden.

Wenn Sie also ein Squash-Commit erreichen und sagen "Diese Entwicklung wurde von Zweig XYZ gequetscht", ist es ein großer Schmerz, zu sehen, was in XYZ enthalten ist.

Ja, aber das ist kein Problem der GUI, sondern des Squash-Commits. Wenn Sie einen Squash verwenden, bleibt der Zweig des Feature-Zweigs hängen und Sie erstellen ein ganz neues Commit für master. Dies bricht die Struktur auf zwei Ebenen und schafft ein großes Durcheinander.

Sie wollen also, dass diese großen, langen Entwicklungszweige zusammengeführt werden, immer mit einem Merge-Commit.

Und sie haben absolut Recht. Aber sie werden nicht "zusammengeführt in", sondern nur zusammengeführt. Eine Zusammenführung ist eine wirklich ausgewogene Sache, es gibt keine bevorzugte Seite, die "in" die andere zusammengeführt wird (git checkout A ; git merge B Ist genau das gleiche wie git checkout B ; git merge A, Abgesehen von geringfügigen visuellen Unterschieden wie dem Vertauschen der Zweige in git log usw.).

Sie wollen keinen Verlauf, auf den der Hauptzweig nicht sofort zugreifen kann.

Welches ist völlig richtig. Zu einer Zeit, in der es keine nicht zusammengeführten Features gibt, gibt es einen einzelnen Zweig master mit einem umfangreichen Verlauf, der alle Commit-Commit-Zeilen enthält, die es je gab, und der von Anfang an auf das Commit git init Zurückgeht Zeit (beachten Sie, dass ich es im letzten Teil dieses Absatzes ausdrücklich vermieden habe, den Begriff "Zweige" zu verwenden, da der Verlauf zu diesem Zeitpunkt nicht mehr "Zweige" ist, obwohl das Festschreibungsdiagramm ziemlich verzweigt wäre).

Ich hasse diese Idee;

Dann haben Sie ein bisschen Schmerzen, da Sie gegen das von Ihnen verwendete Werkzeug arbeiten. Der Ansatz git ist sehr elegant und leistungsstark, insbesondere im Bereich Verzweigung/Zusammenführung. Wenn Sie es richtig machen (wie oben erwähnt, insbesondere mit --no-ff), ist es anderen Ansätzen sprunghaft überlegen (z. B. dem Subversion-Durcheinander, parallele Verzeichnisstrukturen für Zweige zu haben).

es bedeutet ein endloses, nicht befahrbares Gewirr paralleler Entwicklungsgeschichte.

Endlos, parallel - ja.

Nicht befahrbar, Gewirr - nein.

Aber ich sehe nicht, welche Alternative wir haben.

Warum nicht jeden Tag wie der Erfinder von git arbeiten, wie es Ihre Kollegen und der Rest der Welt tun?

Haben wir hier eine andere Möglichkeit, als ständig Nebenzweige mit Merge-Commits zu Master zusammenzuführen? Oder gibt es einen Grund, warum die ständige Verwendung von Merge-Commits nicht so schlimm ist, wie ich befürchte?

Keine anderen Optionen; nicht so schlimm.

10
AnoE

Persönlich ziehe ich es vor, meine Entwicklung in einem Fork durchzuführen und dann Anforderungen zum Zusammenführen in das primäre Repository abzurufen.

Das bedeutet, dass ich das voll und ganz tun kann, wenn ich meine Änderungen auf den Master zurücksetzen oder einige WIP-Commits unterdrücken möchte. Oder ich kann einfach verlangen, dass auch meine gesamte Geschichte zusammengeführt wird.

Was ich wie zu tun habe, ist meine Entwicklung auf einem Zweig zu machen, aber häufig gegen master/dev zu stoßen. Auf diese Weise erhalte ich die neuesten Änderungen vom Master, ohne eine Reihe von Merge-Commits in my zu haben oder mit einer ganzen Reihe von Merge-Konflikten fertig zu werden, wenn es Zeit ist, zum Master zusammenzuführen.

Um Ihre Frage explizit zu beantworten:

Haben wir hier eine andere Möglichkeit, als ständig Nebenzweige mit Merge-Commits zu Master zusammenzuführen?

Ja - Sie können sie einmal pro Zweig zusammenführen (wenn die Funktion oder das Update "abgeschlossen" ist). Wenn Sie die Zusammenführungs-Commits in Ihrem Verlauf nicht mögen, können Sie nach einer endgültigen Rebase einfach eine Schnellvorlauf-Zusammenführung auf dem Master durchführen.

1
Wayne Werner