Benannte Zweige gegen mehrere Repositorys


130

Wir verwenden derzeit Subversion auf einer relativ großen Codebasis. Jede Version erhält einen eigenen Zweig, und Korrekturen werden für den Trunk durchgeführt und mithilfe von in Zweigstellen migriertsvnmerge.py

Ich glaube, es ist an der Zeit, zu einer besseren Quellcodeverwaltung überzugehen, und ich habe eine Weile mit Mercurial gespielt.

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

In beiden Fällen scheint es so, als würde ich so etwas wie eine 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?

Antworten:


129

Der größte Unterschied besteht darin, wie die Filialnamen in der Historie aufgezeichnet werden. Bei benannten Zweigen ist der Zweigname in jedes Änderungsset eingebettet und wird somit zu einem unveränderlichen Teil des Verlaufs. Bei Klonen gibt es keine permanente Aufzeichnung darüber, woher ein bestimmter Änderungssatz stammt.

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

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

[a] --- [b]

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

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

Mittelwert , während jemand setzt [c]und [d]in das Repository, also wenn Sie ziehen Sie eine Geschichte Graph wie diese:

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

Hier gibt es zwei Köpfe in einem einzigen Repository. Ihre Arbeitskopie spiegelt immer ein einzelnes Änderungsset wider, das sogenannte übergeordnete Änderungsset der Arbeitskopie. Überprüfen Sie dies mit:

% hg parents

Nehmen wir an, es wird berichtet [y]. Sie können die Köpfe mit sehen

% hg heads

und dies wird berichten [y]und [d]. Wenn Sie Ihr Repository auf ein sauberes Auschecken von aktualisieren möchten, [d]tun Sie dies einfach (ersetzen Sie es [d]durch die Revisionsnummer für [d]):

% hg update --clean [d]

Sie sehen dann diesen hg parentsBericht [d]. Dies bedeutet, dass Ihr nächstes Commit [d]als übergeordnetes Element gilt. Auf diese Weise können Sie einen Fehler beheben, den Sie im Hauptzweig bemerkt haben, und einen Änderungssatz erstellen [e]:

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

Um nur den Änderungssatz zu pushen [e], müssen Sie dies tun

% hg push -r [e]

Wo [e]ist der Changeset-Hash? Standardmäßig hg pushwird einfach die Repositories vergleichen und sehen , dass [x], [y]und [e]fehlen, aber Sie könnten nicht teilen möchten [x]und [y]noch.

Wenn der Bugfix auch Sie betrifft, möchten Sie ihn mit Ihrem Feature-Zweig zusammenführen:

% hg update [y]
% hg merge

Dadurch sieht Ihr Repository-Diagramm folgendermaßen aus:

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

Wo [z]ist die Verschmelzung zwischen [y]und [e]. Sie hätten sich auch dafür entscheiden können, den Ast wegzuwerfen:

% hg strip [x]

Mein Hauptpunkt dieser Geschichte ist folgender: Ein einzelner Klon kann leicht mehrere Entwicklungsspuren darstellen. Dies war schon immer für "plain hg" ohne Verwendung von Erweiterungen der Fall. Die Lesezeichenerweiterung ist jedoch eine große Hilfe. Hiermit können Sie Änderungssätzen Namen (Lesezeichen) zuweisen. Im obigen Fall möchten Sie ein Lesezeichen auf Ihrem Entwicklungskopf und eines auf dem vorgelagerten Kopf. Lesezeichen können mit Mercurial 1.6 verschoben und gezogen werden und sind in Mercurial 1.8 zu einer integrierten Funktion geworden.

Wenn Sie sich für die Erstellung von zwei Klonen entschieden hätten, hätte Ihr Entwicklungsklon nach der Erstellung folgendermaßen ausgesehen [x]und [y]:

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

Und Ihr Upstream-Klon enthält:

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

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

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

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

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

und zusammenführen:

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

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

Benannte Zweige kamen hier nicht wirklich ins Spiel, weil sie ziemlich optional sind. Mercurial selbst wurde jahrelang mit zwei Klonen entwickelt, bevor wir auf benannte Zweige umstellten. Wir unterhalten zusätzlich zum 'Standard'-Zweig einen Zweig namens' Stable 'und machen unsere Releases basierend auf dem' Stable'-Zweig. Auf der Standard-Verzweigungsseite im Wiki finden Sie eine Beschreibung des empfohlenen Workflows.


1
Wenn das Änderungsset von einem anderen Benutzer stammt, wurde es aufgezeichnet, sodass die Verwendung von Klonen nichts Schlechtes ist. Wenn Sie ein neues Feature veröffentlichen, ist es oft uninteressant zu wissen, dass Sie dies aus einem separaten Repo heraus getan haben. Es gibt auch eine lokale Zweigstellenerweiterung, mit der Sie nur eine lokale Zweigstelle erhalten. Nützlich beim Klonen des Repos ist mit hohen Kosten (Zeit / Raum) verbunden.
Johannes Rudolph

2
Verweis auf: "Klone eignen sich hervorragend für schnelle Experimente" - Nein, das sind sie nicht! Was ist, wenn Sie ein paar Tausend Dateien im Repo haben? Das Klonen dauert ewig (jederzeit über 1 Minute), während der Zweigwechsel nur einen Moment (<1 Sekunde) dauert. Wenn Sie weiterhin benannte Zweige verwenden, wird das Änderungsprotokoll verschmutzt. Ist es nicht eine Sackgasse? Oder fehlt mir etwas?
Seler

Okay Seler; Klingt nach einer Modifikation seines ursprünglichen Arguments; Klone sind gut geeignet, wenn der Overhead mehrerer vollständiger Kopien für Sie nicht wichtig ist oder wenn Sie die Symlinks / Hardlinks von hg verwenden können, um die Kosten für separate lokale Arbeitskopien pro Zweig zu senken.
Warren P

@seler: Sie haben völlig Recht, dass Klone unpraktisch sind, wenn der Code groß ist. Lesezeichen sind dann die Lösung.
Martin Geisler

29

Ich denke, Sie wollen die gesamte Geschichte in einem Repo. Das Laichen eines kurzfristigen Repos ist für kurzfristige Experimente gedacht, nicht für Großereignisse wie Veröffentlichungen.

Eine der Enttäuschungen von Mercurial ist, dass es keinen einfachen Weg zu geben scheint, einen kurzlebigen Zweig zu schaffen, damit zu spielen, ihn aufzugeben und den Müll zu sammeln. Zweige sind für immer. Ich sympathisiere damit, gitdass ich die Geschichte niemals aufgeben möchte, aber die supergünstigen Einwegfilialen sind ein Merkmal, das ich wirklich gerne sehen würde hg.


20
Sie können sehr einfach einen solchen Feature-Zweig erstellen: "hg update" an Ihrem Verzweigungspunkt, bearbeiten und "hg commit". Sie haben eine abweichende Entwicklungslinie neu erstellt - neue Commits werden diesen Zweig erweitern. Verwenden Sie "hg clone -r", um es zu entfernen, oder entfernen Sie es inline mit "hg strip". Seien Sie also bitte nicht enttäuscht oder besuchen Sie die Mercurial-Mailinglisten mit Ihren Feature-Anfragen.
Martin Geisler

8
Es sieht so aus, als ob hg stripich es will. Warum können Zweigstellen für Online-Dokumentationsansprüche nicht gelöscht werden?
Norman Ramsey

11
Siehe auch diesen Blog-Beitrag für eine Erklärung darüber, wie Mercurial in gewisser
Martin Geisler

9
Sie können einen benannten Zweig mit schließen hg ci --close-branch.
Andrey Vlasovskikh

3
@Norman Ramsey: Wenn Leute sagen, dass Zweige nicht gelöscht werden können, bedeutet dies, dass Sie den in den Änderungssätzen eingebetteten Zweignamen nicht ändern können. Eine Änderung setzt uns nein auf einen Zweig, es definiert einen Zweig. Sie müssen das Änderungsset löschen und mit einem anderen Zweignamen neu erstellen, wenn Sie es in einen anderen Zweig "verschieben" möchten.
Martin Geisler

14

Sie sollten beides tun .

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

Lassen Sie dann einen Klon pro Release-Zweig erstellen und testen.

Eine wichtige Anmerkung ist, dass Sie, selbst wenn Sie mehrere Repositorys verwenden, das transplantVerschieben von Änderungssätzen zwischen diesen vermeiden sollten, da 1) der Hash geändert wird und 2) Fehler auftreten können, die sehr schwer zu erkennen sind, wenn zwischen den Änderungssätzen widersprüchliche Änderungen bestehen Transplantation und der Zielzweig. Sie möchten stattdessen die übliche Zusammenführung durchführen (und ohne Vorab-Zusammenführung: Überprüfen Sie die Zusammenführung immer visuell), was zu dem führt, was @mg am Ende seiner Antwort gesagt hat:

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

Wenn Sie mehrere Repositorys verwenden, enthält das "Trunk" -Repositorium (oder Standard-, Haupt-, Entwicklungs- usw. ) ALLE Änderungssätze in ALL - Repositories. Jedes Release- / Zweig-Repository ist einfach ein Zweig im Trunk, der auf die eine oder andere Weise wieder zum Trunk zusammengeführt wird, bis Sie ein altes Release zurücklassen möchten. Daher besteht der einzige wirkliche Unterschied zwischen diesem Haupt-Repo und dem einzelnen Repo im benannten Zweigschema einfach darin, ob Zweige benannt sind oder nicht.

Das sollte deutlich machen, warum ich "mit einem Repo beginnen" sagte. Dieses einzelne Repo ist der einzige Ort, an dem Sie jemals nach Änderungen in einer Version suchen müssen . Sie können Änderungssätze in den Release-Zweigen für die Versionierung weiter kennzeichnen. Es ist konzeptionell klar und einfach und vereinfacht den Systemadministrator, da es das einzige ist, das unbedingt jederzeit verfügbar und wiederherstellbar sein muss.

Dann müssen Sie jedoch noch einen Klon pro Zweig / Release verwalten, den Sie erstellen und testen müssen. Es ist so trivial wie möglich hg clone <main repo>#<branch> <branch repo>, und dann werden hg pullim Zweig-Repo nur neue Änderungssätze für diesen Zweig abgerufen (plus Ahnen-Änderungssätze für frühere Zweige, die zusammengeführt wurden).

Dieses Setup am besten passt das Linux - Modell begehen Kernel Single Puller (sieht es nicht gut fühlen , wie Herr Linus zu handeln. Bei uns nennen wir die Rolle Integrator ), da die Haupt Repo das einzige , was Entwickler benötigen , um Klon ist und die Abzieher muss hineinziehen. Die Wartung der Filialrepos dient ausschließlich dem Release-Management und kann vollständig automatisiert werden. Entwickler müssen niemals von den Zweigstellen-Repos ziehen.


Hier ist das Beispiel von @ mg, das für dieses Setup neu erstellt wurde. Startpunkt:

[a] - [b]

Erstellen Sie einen benannten Zweig für eine Release-Version, z. B. "1.0", wenn Sie zur Alpha-Version gelangen. Beheben Sie Fehlerbehebungen:

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

(1.0)ist kein wirklicher Änderungssatz, da der benannte Zweig erst existiert, wenn Sie ihn festschreiben. (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, toten Release-Zweigs, wie zuvor erwähnt). Wenn Sie also neue Änderungssätze für Release-Zweige haben, müssen Sie diese sofort wieder in den Standardzweig (oder einen späteren Release-Zweig) zurückführen. Dies garantiert, dass alle Fehlerbehebungen in einer Version auch in allen späteren Versionen enthalten sind.

In der Zwischenzeit wird die Entwicklung des Standardzweigs in Richtung der nächsten Version fortgesetzt:

          ------- [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 das ist der 1.0-Zweigklon:

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

Jetzt ist es eine Übung, den nächsten Release-Zweig hinzuzufügen. Wenn es 2.0 ist, wird es definitiv vom Standard abweichen. Wenn es 1.1 ist, können Sie zwischen 1.0 und Standard wählen. Unabhängig davon sollte jeder neue Änderungssatz für 1.0 zuerst mit dem nächsten Zweig und dann mit dem Standardzweig zusammengeführt werden. Dies kann automatisch erfolgen, wenn kein Konflikt vorliegt, der 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. Einziges autorisierendes Repository, das den vollständigen Änderungssatz und den Versionsverlauf enthält.
  2. Klares und vereinfachtes Release-Management.
  3. Klarer und vereinfachter Workflow für Entwickler und Integratoren.
  4. Erleichtern Sie Workflow-Iterationen (Codeüberprüfungen) und Automatisierung (automatische leere Zusammenführung).

UPDATE hg selbst macht das : Das Haupt-Repo enthält die Standard- und Stable-Zweige, und das Stable-Repo ist der Stone-Branch-Klon. Es wird jedoch kein versionierter Zweig verwendet, da Versions-Tags entlang des stabilen Zweigs für die Release-Verwaltung gut genug sind.


5

Der Hauptunterschied ist, soweit ich weiß, etwas, das Sie bereits angegeben haben: Named Branched befinden sich in einem einzigen Repository. Benannte Filialen haben alles an einem Ort zur Hand. Separate Repos sind kleiner und leicht zu bewegen. Der Grund dafür ist, dass es keinen klaren Gewinner gibt. Welche Argumente für Sie am sinnvollsten sind, sollten Sie wahrscheinlich wählen, da ihre Umgebung Ihrer wahrscheinlich am ähnlichsten ist.


2

Ich denke, es ist eindeutig eine pragmatische Entscheidung, abhängig von der aktuellen Situation, z. B. der Größe eines Features / Redesigns. Ich denke, Gabeln sind wirklich gut für Mitwirkende mit noch nicht festgeschriebenen Rollen, um dem Entwicklerteam beizutreten, indem sie ihre Eignung mit vernachlässigbarem technischen Aufwand unter Beweis stellen.


0

Ich würde wirklich davon abraten, benannte Zweige für Versionen zu verwenden. Dafür sind Tags wirklich da. Benannte Zweige sind für lang anhaltende Umleitungen gedacht, wie ein stableZweig.

Warum also nicht einfach Tags verwenden? Ein einfaches Beispiel:

  • Die Entwicklung erfolgt in einem einzigen Zweig
  • Wenn eine Version erstellt wird, kennzeichnen Sie sie entsprechend
  • Von dort aus geht die Entwicklung einfach weiter
  • Wenn Sie in einer bestimmten Version einige Fehler beheben müssen (oder was auch immer), aktualisieren Sie einfach das Tag, nehmen Sie Ihre Änderungen vor und legen Sie fest

Dadurch entsteht ein neuer, unbenannter Kopf auf dem defaultZweig, auch bekannt als. ein anonymer Zweig, der in hg vollkommen in Ordnung ist. Sie können dann jederzeit die Bugfix-Commits wieder in den Hauptentwicklungspfad einfügen. Keine Notwendigkeit für benannte Zweige.


Dies hängt sehr stark von Ihrem Prozess ab. Eine Web-App funktioniert beispielsweise gut mit einer stabilen / Test- / Entwicklungszweighierarchie. Beim Erstellen von Desktop-Software haben wir normalerweise einen Entwicklungszweig (Standard) sowie ein bis drei (!) Verschiedene Zweige in der Wartung. Es ist schwer vorherzusagen, wann wir einen Zweig erneut besuchen müssen, und es ist eine gewisse Eleganz, wenn ein Zweig eine major.minor-Version verfolgt.
James Emerton
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.