Mein Büro versucht herauszufinden, wie wir mit Zweigaufteilungen und Zusammenschlüssen umgehen, und wir sind auf ein großes Problem gestoßen.
Wir haben es mit langfristigen Nebenzweigen zu tun - bei denen ein paar Leute an einem Nebenzweig arbeiten, der sich vom Meister trennt, den wir für ein paar Monate entwickeln, und wenn wir einen Meilenstein erreichen, synchronisieren wir die beiden.
Nun, meiner Meinung nach, besteht die natürliche Art und Weise, damit umzugehen darin, die Seitenzweige zu einem einzigen Commit zusammenzudrücken. master
geht weiter voran; wie es sollte - wir werfen nicht rückwirkend Monate paralleler Entwicklung in master
die Geschichte. Und wenn jemand eine bessere Auflösung für die Geschichte des Seitenzweigs braucht, dann ist natürlich alles noch da - es ist einfach nicht master
drin, es ist im Seitenzweig.
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 gestampft XYZ
", ist es ein großer Schmerz, nachzusehen, was drin ist XYZ
.
Bei SourceTree bereitet mir das große Kopfzerbrechen: Wenn Sie aktiviert sind und den Verlauf anzeigen master
möchten master+devFeature
, müssen Sie entweder master+devFeature
alle Dateien auschecken (berühren, die unterschiedlich sind) oder Blättern Sie durch ein Protokoll, in dem ALLE Zweigstellen Ihres Repositorys gleichzeitig angezeigt werden, bis Sie den richtigen Ort gefunden haben. Und viel Glück beim Herausfinden, wo Sie sich gerade befinden.
Zu Recht möchten meine Teamkollegen nicht, dass die Entwicklungsgeschichte so unzugänglich ist. Sie wollen also, dass diese großen, langen Entwicklungs-Sidebranches zusammengeführt werden, immer mit einem Merge-Commit. Sie möchten keine Historie, auf die nicht sofort von der Hauptniederlassung aus zugegriffen werden kann.
Ich hasse diese Idee. es bedeutet ein endloses, nicht zu überwindendes Gewirr paralleler Entwicklungsgeschichte. Aber ich sehe nicht, welche Alternative wir haben. Und ich bin ziemlich ratlos. Das scheint fast alles zu blockieren, was ich über gutes Filialmanagement weiß, und es wird für mich eine ständige Enttäuschung, wenn ich keine Lösung finde.
Haben wir hier eine andere Möglichkeit, als Sidebranches ständig mit Merge-Commits zum Master zusammenzuführen? Oder gibt es einen Grund, warum es nicht so schlimm ist, ständig Merge-Commits zu verwenden, wie ich befürchte?
quelle
git log master+bugfixDec10th
merge --no-ff
was du willst Anmaster
sich haben Sie einen Commit, der beschreibt, was sich in der Verzweigung geändert hat, aber alle Commits existieren noch und sind HEAD übergeordnet.Antworten:
Obwohl ich Git in der Befehlszeile verwende, muss ich mich Ihren Kollegen anschließen. 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 löscht möglicherweise nicht erreichbare Commits.
Aktionen wie Umbasieren, Kirschpflücken oder Quetschen, Löschen oder Umschreiben des Verlaufs. Insbesondere verweisen die resultierenden Commits nicht mehr auf die ursprünglichen Commits. Bedenken Sie:
[1]: Auf einigen Git-Servern können Zweige vor versehentlichem Löschen geschützt werden, aber ich bezweifle, dass Sie alle Ihre Feature-Zweige für immer behalten möchten.
Jetzt können Sie dieses Commit nicht mehr nachschlagen - es existiert einfach nicht.
Das Referenzieren eines Zweignamens in einer Festschreibungsnachricht ist noch schlimmer, da Zweignamen für ein Repository lokal sind. Was sich
master+devFeature
in Ihrer lokalen Kasse befindet, könntedoodlediduh
in meiner sein. Bei Zweigen handelt es sich lediglich um verschobene Beschriftungen, die auf ein Commit-Objekt verweisen.Unter allen Methoden zum Umschreiben von Verlaufsdaten ist das Umbasieren am vorteilhaftesten, da es die vollständigen Festschreibungen mit dem gesamten Verlauf dupliziert und nur eine übergeordnete Festschreibung ersetzt.
Dass die
master
Historie die gesamte Historie aller darin zusammengeführten Branchen umfasst, ist gut so, denn das repräsentiert die Realität. [2] Wenn parallel entwickelt wurde, sollte dies im Protokoll sichtbar sein.[2]: Aus diesem Grund bevorzuge ich auch explizite Merge-Commits gegenüber linearisierten, aber letztendlich gefälschten Verlaufsdaten, die sich aus einer Neugründung ergeben.
git log
Versuchen Sie in der Befehlszeile, 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-Log-Tool zu schreiben, das den Commit-Graphen durchläuft, aber es ist im Allgemeinen unmöglich zu beantworten, ob dieses Commit ursprünglich für diesen oder diesen Zweig festgeschrieben wurde. Das erste übergeordnete Element eines Zusammenführungs-Commits ist das vorherigeHEAD
, dh das Commit in dem Zweig, in dem Sie zusammenführen. Dies setzt jedoch voraus, dass Sie keine umgekehrte Zusammenführung vom Master zum Feature-Zweig und dann eine schnelle Weiterleitung des Masters zum Merge durchgeführt haben.Die beste Lösung für langfristige Zweigniederlassungen ist die Vermeidung von Zweigniederlassungen, die erst nach einigen Monaten zusammengeführt werden. Das Zusammenführen ist am einfachsten, wenn die Änderungen kürzlich vorgenommen wurden und gering sind. Im Idealfall werden Sie mindestens einmal pro Woche zusammengeführt. Kontinuierliche Integration (wie bei Extreme Programming, nicht wie bei „Richten wir einen Jenkins-Server ein“) schlägt sogar mehrere Zusammenführungen pro Tag vor, dh keine separaten Feature-Zweige zu verwalten, sondern einen Entwicklungszweig als Team zu teilen. Das Zusammenführen, bevor ein Feature einer Qualitätssicherung unterzogen wird, erfordert, dass das Feature hinter einem Feature-Flag verborgen ist.
Im Gegenzug ermöglicht die 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 alle Branchen einbezogen werden. Wenn eine Änderung einen Code beschädigt, werden nur ein paar Arbeitstage und nicht ein paar Monate beansprucht.
Das Umschreiben der Geschichte kann für wirklich große Projekte sinnvoll sein, wenn mehrere Millionen Codezeilen und Hunderte oder Tausende von aktiven Entwicklern vorhanden sind. Es ist fraglich, warum ein so großes Projekt ein einzelnes Git-Repo sein müsste, anstatt in separate Bibliotheken aufgeteilt zu werden. In diesem Maßstab ist es jedoch praktischer, wenn das zentrale Repo nur „Releases“ der einzelnen Komponenten enthält. Zum Beispiel verwendet der Linux-Kernel Squashing, um die Hauptgeschichte übersichtlich zu halten. Bei einigen Open Source-Projekten müssen Patches per E-Mail gesendet werden, anstatt sie auf Git-Ebene zusammenzuführen.
quelle
git bisect
, damit er über ein Uber-Commit von 10.000 Zeilen aus einem Nebenzweig ermittelt wird.Die Antwort von Amon gefällt mir , aber ich war der Meinung, dass ein kleiner Teil viel wichtiger ist: Sie können den Verlauf beim Anzeigen von Protokollen leicht vereinfachen, um Ihre Anforderungen zu erfüllen, aber andere können den Verlauf beim Anzeigen von Protokollen nicht hinzufügen, um ihre Anforderungen zu erfüllen. Aus diesem Grund ist es vorzuziehen, die Historie so zu belassen, wie sie aufgetreten ist.
Hier ist ein Beispiel aus einem unserer Repositories. Wir verwenden ein Pull-Request-Modell, sodass jede Funktion Ihren langjährigen Filialen im Verlauf ähnelt, auch wenn sie normalerweise nur eine Woche oder weniger ausgeführt werden. Einzelne Entwickler entscheiden sich manchmal dafür, ihre Historie vor dem Zusammenführen zu zerquetschen, aber wir stimmen häufig mit Funktionen überein, was relativ ungewöhnlich ist. Hier sind die Top-Commits
gitk
, die mit Git ausgelieferte GUI:Ja, ein bisschen durcheinander, 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 anzeigen möchten, die jeweils nur eine Pull-Anforderung enthält, können wir uns die folgende Ansicht ansehen, die dem
git log --first-parent
Befehl entspricht:git log
bietet viele weitere Optionen, mit denen Sie genau die gewünschten Ansichten erhalten.gitk
kann ein beliebigesgit 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, wie Sie sie richtig verwenden, anstatt Ihre bevorzugtegit log
Ansicht für alle Benutzer zum Zeitpunkt der Zusammenführung zu erzwingen .quelle
merge --no-ff
- verwende keine Schnellvorlauf-Zusammenführungen, sondern erstelle immer ein Zusammenführungs-Commit, damit--first-parent
etwas funktioniertMein erster Gedanke ist - mach das nicht einmal, es sei denn, es ist absolut notwendig. Ihre Zusammenführungen müssen manchmal schwierig sein. Halten Sie Niederlassungen unabhängig und so kurzlebig wie möglich. Dies ist ein Zeichen dafür, dass Sie Ihre Storys in kleinere Implementierungsteile aufteilen müssen.
In dem Fall, dass Sie dies tun müssen, ist es möglich, git mit der Option --no-ff zusammenzuführen, so dass die Historien auf 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 zu verwenden, fand ich es etwas seltsam, dass die Branch-Commits nach dem Zusammenführen in derselben Historie wie der Haupt-Branch erschienen sind. Es war ein wenig beunruhigend, weil es nicht so schien, als gehörten diese Verpflichtungen in diese Geschichte. Aber in der Praxis ist das überhaupt nicht schmerzhaft, wenn man bedenkt, dass der Integrationszweig genau das ist - sein ganzer Zweck ist es, die Feature-Zweige zu kombinieren. In unserem Team werden wir nicht gequetscht, und wir führen häufig Merge-Commits durch. Wir verwenden --no-ff die ganze Zeit, um sicherzustellen, dass die genaue Historie eines Features leicht zu sehen ist, falls wir es untersuchen möchten.
quelle
git merge --no-ff
git merge --no-ff
. Wenn Sie gitflow verwenden, wird dies zur Standardeinstellung.Lassen Sie mich Ihre Punkte direkt und klar beantworten:
Normalerweise möchten Sie Ihre Filialen nicht monatelang nicht synchronisieren lassen.
Ihr Feature-Zweig hat sich abhängig von Ihrem Workflow von etwas verzweigt. Nennen wir es
master
der Einfachheit halber einfach. Wann immer Sie sich zum Meister verpflichten, können und sollten Sie es jetzt tungit checkout long_running_feature ; git rebase master
. Dies bedeutet, dass Ihre Niederlassungen von Entwurf immer synchron sind.git rebase
ist auch hier das richtige. Es ist kein Hack oder etwas Seltsames oder Gefährliches, sondern ganz 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 einer anderen Stelle gespeichert wird (in Ihrem Ticketsystem oder, wenn die Notwendigkeit groß ist, in einemgit tag
...).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 Elternteilen - dem
master
Kopf und dem Zweigkopf zum Zeitpunkt des Zusammenschlusses.Stellen Sie sicher, dass Sie die
--no-ff
Option angeben . Das Zusammenführen ohne--no-ff
sollte in Ihrem Szenario strengstens untersagt sein. Leider--no-ff
ist das nicht die Standardeinstellung; aber ich glaube, es gibt eine Option, die Sie einstellen können, die es so macht. Sehen Sie,git help merge
was--no-ff
tut (kurz: es aktiviert das Verhalten, das ich im vorherigen Absatz beschrieben habe), es ist entscheidend.Absolut nicht - Sie werfen niemals etwas "in die Geschichte" einer Branche, insbesondere nicht mit einem Merge-Commit.
Bei einem Merge-Commit ist es immer noch da. Nicht im Master, sondern im Sidebranch, klar erkennbar als eines der Elternteile des Merge Commits und für die Ewigkeit erhalten, wie es sein sollte.
Sehen Sie, was ich getan habe? Alle Dinge , die Sie für Ihre Squash beschreiben begehen , sind genau dort mit der Zusammenführung
--no-ff
begehen.(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 als auch). Aber bitte selbst einen gefallen tun und zumindest versuchen ,
git gui
einmal. Es ist so viel effizienter für die Kommissionierung Linien, große stücke usw. für das Hinzufügen / Verhängnis hinzufügt.)Das ist so, weil das, was du versuchst, total gegen den Geist von ist
git
.git
baut vom Kern auf einem "gerichteten azyklischen Graphen" auf, was bedeutet, dass sich viele Informationen in der Eltern-Kind-Beziehung von Commits befinden. Bei Zusammenführungen bedeutet dies, dass zwei Elternteile und ein Kind tatsächlich zusammengeführt werden. Die GUIs Ihrer Kollegen werden in Ordnung sein, sobald Sieno-ff
Merge-Commits verwenden.Ja, aber das ist kein Problem der Benutzeroberfläche, sondern des Squash-Commits. Wenn Sie einen Squash verwenden, lässt der Kopf des Feature-Zweigs hängen und es wird ein ganz neues Commit erstellt
master
. Dies bricht die Struktur auf zwei Ebenen und schafft ein großes Durcheinander.Und sie haben absolut recht. Aber sie nicht „verschmolzen sind in “, werden sie verschmolzen gerade. Eine Zusammenführung ist eine wirklich ausgewogene Sache, es hat keine bevorzugte Seite , die „in“ der anderen verschmolzen wird (
git checkout A ; git merge B
ist genau das gleiche wie mitgit checkout B ; git merge A
Ausnahme kleinerer visuellen Unterschiede wie die Zweige um in getauscht werdengit log
etc.).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 Feature- Festschreibungszeilen enthält, die es je gab. Dabei wurde auf diegit init
Festschreibung von Anfang an zurückgegriffen. Verzweigungen "im letzten Teil dieses Absatzes, da der Verlauf zu diesem Zeitpunkt nicht mehr" Verzweigungen "ist, obwohl das Festschreibungsdiagramm ziemlich verzweigt wäre).Dann haben Sie ein bisschen Schmerzen, da Sie gegen das von Ihnen verwendete Werkzeug arbeiten. Der
git
Ansatz ist sehr elegant und kraftvoll, insbesondere im Bereich der Verzweigung / Zusammenführung. Wenn Sie es richtig machen (wie oben angedeutet, insbesondere mit--no-ff
), ist es sprunghaft besser als andere Ansätze (z. B. das Subversion-Chaos, parallele Verzeichnisstrukturen für Zweige zu haben).Endlos, parallel - ja.
Unnavigable, Tangle - nein.
Warum nicht
git
jeden Tag so arbeiten wie der Erfinder von , Ihre Kollegen und der Rest der Welt?Keine anderen Optionen; nicht so schlimm.
quelle
Wenn Sie einen langfristigen Seitenzweig zerquetschen, verlieren Sie viele Informationen.
Was ich tun würde, ist zu versuchen, den Master in den langfristigen Nebenzweig zurückzugliedern, bevor der Nebenzweig in den Master zusammengeführt wird . Auf diese Weise behalten Sie jedes Commit im Master bei, während der Commit-Verlauf linear und verständlicher wird.
Wenn ich das bei jedem Commit nicht so einfach machen könnte, würde ich es nicht linear sein lassen , um den Entwicklungskontext klar zu halten. Meiner Meinung nach hatte die Nichtlinearität eine reale Bedeutung, wenn ich während des Zurücksetzens des Masters in die Sidebranche ein Problem hatte. Das heißt, es wird einfacher zu verstehen sein, was passiert ist, falls ich in die Geschichte eintauchen muss. Ich habe auch den unmittelbaren Vorteil, dass ich keinen Rebase machen muss.
quelle
rebase
. Unabhängig davon, ob es der beste Ansatz ist oder nicht (ich persönlich habe noch keine großartigen Erfahrungen damit gemacht, obwohl ich ihn nicht viel genutzt habe), scheint er definitiv dem am nächsten zu sein, was OP wirklich zu wollen scheint - insbesondere a Kompromiss zwischen einem Speicherauszug für einen nicht in Ordnung befindlichen Verlauf und dem vollständigen Ausblenden dieses Verlaufs.Persönlich bevorzuge ich es, meine Entwicklung in einer Abzweigung durchzuführen und dann Anforderungen zum Zusammenführen in das primäre Repository abzurufen.
Das heißt, wenn ich meine Änderungen auf Master zurücksetzen oder einige WIP-Commits quetschen möchte, kann ich das voll und ganz tun. Oder ich kann nur verlangen, dass meine gesamte Geschichte mit einbezogen wird.
Was ich gerne mache, ist meine Entwicklung auf einem Zweig, aber häufig gegen Master / Dev. Auf diese Weise erhalte ich die neuesten Änderungen vom Master, ohne dass eine Reihe von Merge-Commits in meinem Zweig vorhanden sind oder eine ganze Menge von Merge-Konflikten auftreten müssen, wenn es Zeit ist, zum Master zusammenzuführen.
So beantworten Sie Ihre Frage explizit:
Ja - Sie können sie einmal pro Zweig zusammenführen (wenn das Feature oder der Fix "vollständig" ist) oder wenn Sie die Zusammenführungs-Commits nicht in Ihrem Verlauf haben möchten, können Sie nach einer letzten Rebase einfach einen Schnellvorlauf für den Master durchführen.
quelle
Revisionskontrolle ist Garbage-In Garbage-Out.
Das Problem ist, dass die in Bearbeitung befindlichen Arbeiten im Feature-Zweig eine Menge enthalten können: "Lass es uns versuchen ... nein, das hat nicht funktioniert, lass es uns durch das ersetzen." die Geschichte nutzlos zu verschmutzen.
Letztendlich sollte der Verlauf beibehalten werden (ein Teil davon könnte in Zukunft von Nutzen sein), aber nur eine "saubere Kopie" sollte zusammengeführt werden.
Bei Git können Sie dazu zuerst den Feature-Zweig verzweigen (um den gesamten Verlauf zu erhalten), dann den Zweig des Feature-Zweigs vom Master aus (interaktiv) umbasieren und dann den umbasierten Zweig zusammenführen.
quelle
git
und sie sind lokal. Wasfoo
in einem Repo benannt ist, kannbar
in einem anderen Repo benannt sein . Und sie sollen nur vorübergehend sein: Sie möchten Ihr Repo nicht mit Tausenden von Feature-Zweigen überfrachten, die am Leben gehalten werden müssen, um zu vermeiden, dass die Historie verloren geht. Und Sie müssten diese Zweige behalten, um den Verlauf der Referenz beizubehalten, denngit
schließlich werden alle Festschreibungen gelöscht, die für einen Zweig nicht mehr erreichbar sind.