it-swarm.com.de

Benannte Zweige im Vergleich zu mehreren Repositorys

Wir verwenden derzeit Subversion auf einer relativ großen Codebasis. Jedes Release erhält einen eigenen Zweig, und Korrekturen werden für den Trunk durchgeführt und mit svnmerge.py in Versionszweige migriert.

Ich glaube, es ist an der Zeit, die Quellcodeverwaltung zu verbessern, und ich habe eine Weile mit Mercurial gespielt.

Es scheint jedoch zwei Schulen zu geben, die eine solche Release-Struktur mit Mercurial verwalten. Jedes Release erhält ein eigenes Repo, und es werden Korrekturen für den Release-Zweig vorgenommen und in den Hauptzweig (und alle anderen neueren Release-Zweige) verschoben. OR Verwenden Sie benannte Zweige in einem einzelnen Repository (oder mehrere übereinstimmende Kopien) .)

In beiden Fällen scheint es so, als würde ich so etwas wie Transplantation verwenden, um Änderungen für die Aufnahme in die Release-Zweige auszuwählen.

Ich bitte dich; Was sind die relativen Vorzüge jedes Ansatzes?

130
James Emerton

Der größte Unterschied besteht darin, wie die Zweignamen in der Historie aufgezeichnet werden. Bei benannten Zweigen lautet der Zweigname embedded in jedem Changeset und wird somit zu einem unveränderlichen Teil der Historie. Bei Klonen wird keine permanente Aufzeichnung darüber, woher eine bestimmte Änderungsmenge stammt.

Dies bedeutet, dass Klone für schnelle Experimente geeignet sind, bei denen Sie keinen Zweignamen aufzeichnen möchten, und benannte Zweige für langfristige Zweige ("1.x", "2.x" und ähnliche) geeignet sind.

Beachten Sie auch, dass ein einzelnes Repository mehrere leichte Zweige in Mercurial problemlos aufnehmen kann. Solche Repository-Zweige können mit einem Lesezeichen versehen werden, sodass Sie sie leicht wiederfinden können. Nehmen wir an, Sie haben das Unternehmens-Repository geklont, wenn es so aussah:

[a] --- [b]

Sie hacken ab und machen [x] und [y]:

[a] --- [b] --- [x] --- [y]

Bedeutet, während jemand [c] und [d] in das Repository einfügt. Wenn Sie also ziehen, erhalten Sie einen Verlaufsdiagramm wie folgt:

 [x] --- [y] 
 /
[A B C D]

Hier befinden sich zwei Köpfe in einem einzigen Repository. In Ihrer Arbeitskopie wird immer nur ein Änderungssatz angezeigt, der sogenannte übergeordnete Arbeitskopiensatz. Überprüfen Sie dies mit:

% hg parents

Sagen wir, dass es [y] meldet. Sie können die Köpfe mit sehen

% hg heads

und dies wird [y] und [d] melden. Wenn Sie Ihr Repository auf eine saubere Überprüfung von [d] aktualisieren möchten, tun Sie dies einfach (ersetzen Sie [d] mit der Versionsnummer für [d]):

% hg update --clean [d]

Sie sehen dann diesen hg parents-Bericht [d]. Dies bedeutet, dass Ihr nächster Commit [d] als übergeordnetes Element hat. Sie können so einen Fehler beheben, den Sie im Hauptzweig bemerkt haben, und das Änderungsset [e] erstellen:

 [x] --- [y] 
 /
[a] --- [b] --- [c] --- [d] --- [e] 

Um Push-Changeset nur [e] zu übertragen, müssen Sie dies tun

% hg Push -r [e]

dabei ist [e] der Changeset-Hash. Standardmäßig vergleicht hg Push die Repositorys und stellt fest, dass [x], [y] und [e] fehlen, aber Sie möchten [x] und [y] noch nicht freigeben.

Wenn der Bugfix auch auf Sie wirkt, möchten Sie ihn mit Ihrem Funktionszweig zusammenführen:

% hg update [y]
% hg merge

Dadurch wird Ihr Repository-Diagramm so aussehen:

 [x] --- [y] ----------- [z] 
//
[a] --- [b] --- [c] --- [d] --- [e] 

wobei [z] die Zusammenführung zwischen [y] und [e] ist. Sie könnten sich auch dafür entschieden haben, den Zweig wegzuwerfen:

% hg strip [x]

Mein Hauptthema dieser Geschichte ist Folgendes: Ein einzelner Klon kann leicht mehrere Entwicklungspfade darstellen. Dies gilt immer für "plain hg" ohne Verwendung von Erweiterungen. Die bookmarks-Erweiterung ist jedoch eine große Hilfe. Damit können Sie den Changesets Namen (Lesezeichen) zuweisen. Im obigen Fall benötigen Sie ein Lesezeichen für Ihren Entwicklungskopf und eines für den Upstream-Kopf. Lesezeichen können mit Mercurial 1.6 gedrückt und gezogen werden und sind zu einer integrierten Funktion in Mercurial 1.8 geworden.

Wenn Sie sich für zwei Klone entschieden hätten, hätte Ihr Entwicklungsklon nach der Erstellung von [x] und [y] so ausgesehen:

[a] --- [b] --- [x] --- [y]

Ihr Upstream-Klon enthält:

[a] --- [b] --- [c] --- [d]

Sie bemerken jetzt den Fehler und beheben ihn. Hier müssen Sie nicht hg update, da der Upstream-Klon einsatzbereit ist. Sie verpflichten sich und erstellen [e]:

[a] --- [b] --- [c] --- [d] --- [e]

Um den Bugfix in Ihren Entwicklungsklon aufzunehmen, ziehen Sie ihn dort ein:

 [a] --- [b] --- [x] --- [y] 
\
 [c] --- [d] --- [e] 

und verschmelzen:

 [a] --- [b] --- [x] --- [y] --- [z] 
\/
 [c] --- [d] --- [e] 

Das Diagramm sieht möglicherweise anders aus, hat aber dieselbe Struktur und das Endergebnis ist dasselbe. Mit den Klonen musste man die geistige Buchhaltung etwas weniger machen.

Benannte Zweige kamen hier nicht wirklich ins Spiel, weil sie recht optional sind. Mercurial selbst wurde jahrelang mit zwei Klonen entwickelt, bevor wir auf benannte Zweige umstellten. Wir unterhalten einen Zweig namens "stable" zusätzlich zum "default" -Zweig und erstellen unsere Releases auf Basis des "stable" -Zweigs. Eine Beschreibung des empfohlenen Workflows finden Sie auf der Standard-Verzweigungs Seite im Wiki.

129
Martin Geisler

Ich denke, Sie möchten die gesamte Geschichte in einem Repo. Das Ablegen eines kurzfristigen Repos ist für kurzfristige Experimente und nicht für größere Ereignisse wie Veröffentlichungen gedacht.

Eine der Enttäuschungen von Mercurial ist, dass es scheinbar keinen einfachen Weg gibt, einen kurzlebigen Zweig zu schaffen, damit zu spielen, ihn aufzugeben und den Müll zu sammeln. Zweige sind für immer. Ich habe Verständnis dafür, dass ich nie die Geschichte aufgeben möchte, aber die supergünstigen Einwegzweige sind eine git-Funktion, die ich wirklich in hg sehen möchte.

29
Norman Ramsey

Sie sollten beide machen.

Beginnen Sie mit der akzeptierten Antwort von @Norman: Verwenden Sie ein Repository mit einem benannten Zweig pro Release.

Dann haben Sie einen Klon pro Release-Zweig zum Erstellen und Testen.

Eine wichtige Anmerkung: Selbst wenn Sie mehrere Repositorys verwenden, sollten Sie die Verwendung von transplant zum Verschieben von Changesets vermeiden, da 1) sich der Hashwert ändert und 2) Fehler auftreten können, die sehr schwer zu erkennen sind, wenn Änderungen zwischen den Changesets in Konflikt stehen Sie transplantieren und der Zielzweig. Sie möchten stattdessen die übliche Zusammenführung durchführen (und ohne Vorerstellung: Überprüfen Sie die Zusammenführung immer visuell), was zu dem Ergebnis von @mg am Ende seiner Antwort führt:

Das Diagramm sieht möglicherweise anders aus, hat aber dieselbe Struktur und das Endergebnis ist dasselbe.

Wenn Sie mehrere Repositorys verwenden, enthält das "Trunk" -Repository (oder das Standard-, Haupt-, Entwicklungs- oder was auch immer) ALL Änderungsgruppen in ALL Repositorys. Jedes Release/Branch-Repository ist einfach ein Zweig im Trunk, der alle auf die eine oder andere Weise wieder in den Trunk zurückgeführt wird, bis Sie ein altes Release zurücklassen möchten. Daher besteht der einzige wirkliche Unterschied zwischen diesem Haupt-Repo und dem Einzel-Repo im benannten Zweigschema einfach darin, ob Zweige benannt werden oder nicht.

Das sollte deutlich machen, warum ich gesagt habe: "Beginnen Sie mit einem Repo". Dieses einzige Repo ist der einzige Ort, an dem Sie jemals nach allen Änderungen in einem Release suchen müssen. Sie können Changesets auf den Release-Zweigen für die Versionsverwaltung mit Tags versehen. Es ist konzeptionell klar und einfach und vereinfacht die Systemadministration, da es das einzige ist, das absolut verfügbar und jederzeit wiederherstellbar sein muss.

Dann müssen Sie jedoch noch einen Klon pro Zweig/Release pflegen, den Sie erstellen und testen müssen. Es ist so trivial wie möglich hg clone <main repo>#<branch> <branch repo>, und dann wird hg pull im Zweigrepo nur neue Changesets für diesen Zweig abrufen (plus Vorfahr-Changesets für frühere zusammengeführte Zweige).

Dieses Setup passt am besten zum Linux-Kernel-Commit-Modell von single puller (fühlt es sich nicht gut an, sich wie Lord Linus zu verhalten. In unserem Unternehmen nennen wir die Rolle Integrator), da das Haupt-Repo das einzige ist was die Entwickler klonen müssen und der Puller muss ziehen. Die Wartung der Filialen dient ausschließlich der Versionsverwaltung und kann vollständig automatisiert werden. Entwickler müssen niemals von/zu den Zweig-Repos ziehen.


Hier ist @ mgs Beispiel für dieses Setup überarbeitet. Startpunkt:

[a] - [b]

Erstellen Sie einen benannten Zweig für eine Release-Version, sagen Sie "1.0", wenn Sie das Alpha-Release erhalten. Beheben Sie Fehlerbehebungen:

[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

(1.0) ist keine echte Änderungsmenge, da der benannte Zweig erst dann existiert, wenn Sie ein Commit ausführen. (Sie können ein triviales Commit durchführen, z. B. ein Tag hinzufügen, um sicherzustellen, dass benannte Zweige ordnungsgemäß erstellt werden.)

Die Zusammenführung [m1] ist der Schlüssel zu diesem Setup. Im Gegensatz zu einem Entwickler-Repository, in dem eine unbegrenzte Anzahl von Köpfen vorhanden sein kann, möchten Sie NICHT mehrere Köpfe in Ihrem Haupt-Repo haben (mit Ausnahme des alten Dead Release-Zweigs, wie zuvor erwähnt). Immer wenn Sie neue Änderungssets für Release-Zweige haben, müssen Sie diese sofort wieder in den Standard-Zweig (oder einen späteren Release-Zweig) zusammenführen. Dies garantiert, dass alle Fehler in einer Version in allen späteren Versionen enthalten sind.

In der Zwischenzeit geht die Entwicklung im Default-Zweig auf das nächste Release zu:

          ------- [c] - [d]
         /
[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

Und wie üblich müssen Sie die beiden Köpfe im Standardzweig zusammenführen:

          ------- [c] - [d] -------
         /                         \
[a] - [b] ------------------ [m1] - [m2]
         \                 /
          (1.0) - [x] - [y]

Und dies ist der 1.0-Zweig-Klon:

[a] - [b] - (1.0) - [x] - [y]

Nun ist es eine Übung, den nächsten Release-Zweig hinzuzufügen. Wenn es 2.0 ist, wird es definitiv vom Standard abweichen. Wenn es sich um 1,1 handelt, können Sie zwischen 1.0 oder Default verzweigen. Unabhängig davon sollte jedes neue Änderungsset unter 1.0 zuerst mit dem nächsten Zweig zusammengeführt werden, dann mit dem Standard. Dies kann automatisch durchgeführt werden, wenn kein Konflikt vorliegt, was lediglich zu einer leeren Zusammenführung führt.


Ich hoffe, das Beispiel macht meine früheren Punkte klar. Zusammenfassend sind die Vorteile dieses Ansatzes:

  1. Ein einziges autorisiertes Repository, das das vollständige Changeset und den Versionsverlauf enthält.
  2. Klare und vereinfachte Versionsverwaltung.
  3. Klarer und vereinfachter Workflow für Entwickler und Integrator.
  4. Erleichterung von Workflow-Iterationen (Code-Reviews) und Automatisierung (automatisches Leeren-Zusammenführen).

UPDATE hg selbst macht dies : das main repo enthält die voreingestellten und stabilen Zweige, und das stable repo ist der stabile Zweigklon. Es wird jedoch keine versionierte Verzweigung verwendet, da Versionskennungen entlang der stabilen Verzweigung für die Versionsverwaltung gut genug sind.

14
Geoffrey Zheng

Soweit ich weiß, besteht der Hauptunterschied darin, dass Sie bereits festgestellt haben: Verzweigte Namen befinden sich in einem einzigen Repository. Benannte Niederlassungen haben alles an einem Ort zur Hand. Separate Repos sind kleiner und leicht zu bewegen. Der Grund, warum es zwei Denkrichtungen gibt, ist, dass es keinen klaren Gewinner gibt. Welche der Argumente von welcher Seite für Sie am sinnvollsten ist, ist wahrscheinlich die, mit der Sie gehen sollten, da ihre Umgebung wahrscheinlich Ihrer Umgebung am ähnlichsten ist.

5
dwc

Ich denke, es ist eindeutig eine pragmatische Entscheidung, abhängig von der aktuellen Situation, z. die Größe eines Features/Redesigns. Ich denke, Gabeln sind wirklich gut für Mitarbeiter, die noch keine Commit-Rollen haben, um dem Entwicklerteam beizutreten, indem sie ihre Eignung mit vernachlässigbarem technischen Aufwand beweisen.

2
thSoft

Ich würde wirklich davon abraten, benannte Zweige für Versionen zu verwenden. Dafür gibt es wirklich Tags. Benannte Niederlassungen sind für langfristige Ablenkungen gedacht, wie beispielsweise eine stable-Niederlassung.

Warum also nicht einfach Tags verwenden? Ein grundlegendes Beispiel:

  • Die Entwicklung erfolgt in einer einzigen Branche
  • Wenn ein Release erstellt wird, kennzeichnen Sie es entsprechend
  • Die Entwicklung geht von dort aus weiter
  • Wenn Sie in einer bestimmten Version einige Fehler (oder was auch immer) zu beheben haben, aktualisieren Sie einfach das entsprechende Tag, nehmen Sie Ihre Änderungen vor und legen Sie fest

Dadurch wird ein neuer, unbenannter Kopf auf dem Zweig default (aka) erstellt. ein anonymer Zweig, der in hg vollkommen in Ordnung ist. Sie können dann die Bugfix-Commits jederzeit wieder in den Hauptentwicklungspfad einbinden. Benötigte Zweige sind nicht erforderlich.

0
DanMan