Mercurial Repository-Struktur mit schwergewichtigen Kommunikations-, Konfigurationsmanagement- und Testanforderungen für Unternehmen

16

Ich bin ein weiterer Subversion-Benutzer, der Mühe hat, sich in das Tao der verteilten Versionskontrolle einzuarbeiten.

Bei der Verwendung von Subversion war ich ein großer Fan des Projekt-Minor-Ansatzes, und mit den meisten meiner früheren Arbeitgeber haben wir unsere Repository-Filialen strukturiert. Tags & Trunk wie folgt:

branches-+
         +-personal-+
         |          +-alice-+
         |          |       +-shinyNewFeature
         |          |       +-AUTOMATED-+
         |          |                   +-shinyNewFeature
         |          +-bob-+
         |                +-AUTOMATED-+
         |                            +-bespokeCustomerProject
         +-project-+
                   +-shinyNewFeature
                   +-fixStinkyBug
tags-+
     +-m20110401_releaseCandidate_0_1
     +-m20110505_release_0_1
     +-m20110602_milestone
trunk

Innerhalb des eigentlichen Quellbaums würden wir (so etwas wie) die folgende Struktur verwenden:

  (src)-+
        +-developmentAutomation-+
        |                       +-testAutomation
        |                       +-deploymentAutomation
        |                       +-docGeneration
        |                       +-staticAnalysis
        |                       +-systemTest
        |                       +-performanceMeasurement
        |                       +-configurationManagement
        |                       +-utilities
        +-libraries-+
        |           +-log-+
        |           |     +-build
        |           |     +-doc
        |           |     +-test
        |           +-statistics-+
        |           |            +-build
        |           |            +-doc
        |           |            +-test
        |           +-charting-+
        |           |          +-build
        |           |          +-doc
        |           |          +-test
        |           +-distributedComputing-+
        |           |                      +-build
        |           |                      +-doc
        |           |                      +-test
        |           +-widgets-+
        |                     +-build
        |                     +-doc
        |                     +-test
        +-productLines-+
        |              +-flagshipProduct-+
        |              |                 +-coolFeature
        |              |                 +-anotherCoolFeature
        |              |                 +-build
        |              |                 +-doc
        |              |                 +-test
        |              +-coolNewProduct
        +-project-+
                  +-bigImportantCustomer-+
                  |                      +-bespokeProjectOne
                  |                      +-bespokeProjectTwo
                  +-anotherImportantCustomer-+
                                             +-anotherBespokeProject

Die Idee war (und ist), die Struktur des Repositorys zu verwenden, um die Kommunikation zwischen dem Engineering-Team zu strukturieren. der kundenorientierte Teil des Geschäfts und verschiedene andere Stakeholder und Domain-Experten.

Übrigens: Quelldokumente, die sich in einem der "Projekt" -Verzeichnisse befinden, werden nur einmal verwendet (und verdienen Geld). Dokumente, die sich in einem der "productLines" -Verzeichnisse befinden, verdienen so viel Geld, wie ein Produkt aus dieser bestimmten Zeile verkauft wird. Dokumente, die sich in einem der "Bibliotheks" -Verzeichnisse befinden, verdienen so viel Geld, wie Produkte, die sie verwenden, verkauft werden.

Der Begriff der Amortisation von Kosten wird explizit erwähnt, und es wird eine Unterstützung für die Wiederverwendung von Quelldokumenten im gesamten Unternehmen geschaffen.

Dies bedeutet auch, dass es eine gemeinsame Struktur gibt, über die unsere Build-Automatisierungstools arbeiten können. (Unsere Build-Skripte durchsuchen den Quellbaum nach "Build" -Ordnern, in denen sie Konfigurationsdateien finden, die angeben, wie die einzelnen Komponenten erstellt werden sollen. Ein ähnlicher Prozess wird für die Dokumentationserstellung und das Testen ausgeführt.)

Bezeichnenderweise benötigen die Produkte, an denen ich arbeite, in der Regel eine LANGE Zeit, um Leistungstests und Charakterisierungstests durchzuführen. von 20 bis 200 Stunden; Generieren von verarbeiteten Testergebnissen / Zwischendaten zwischen mehreren GB und mehreren TB (die gespeichert und an eine bestimmte Systemkonfiguration gebunden werden müssen, damit die Leistungsverbesserung im Laufe der Zeit gemessen werden kann). Dieses Problem macht das Konfigurationsmanagement zu einer wichtigen Überlegung und macht auch eine Zentralisierung erforderlich, da in der Regel nur begrenzte Rechenressourcen zum Ausführen der Leistungsmessung und der Charakterisierungstests erforderlich sind. (eine kleine Gruppe von 64-128 Kernen).

Als eine letzte Anmerkung; Das kontinuierliche Integrationssystem weiß, dass es einen Build auslösen muss. statische Analyse; Rauch- und Einheitentestlauf bei jeder Änderung des Trunks, bei jeder Änderung eines "Tag" -Zweigs und bei jeder Änderung eines "AUTOMATISIERT" -Zweigs. Auf diese Weise können einzelne Entwickler das CI-System mit ihren persönlichen Filialen nutzen, eine wichtige Funktion, IMHO.

Hier ist meine Frage: Wie kann ich all das oben Genannte mit Mercurial nachbilden (und es, wenn möglich, verbessern)?

--bearbeiten:

Meine derzeitige Denkweise besteht darin, ein zentrales Subversion-Repository zu verwenden, um die Gesamtstruktur zu definieren, aber die Verwendung von hg als Client zuzulassen, damit Entwickler Repos lokal verfügbar haben.

William Payne
quelle
1
Beeindruckend. Eine gute Antwort darauf wird ein sehr langer Aufsatz sein, denke ich.
Ed James
Ich denke, die Schlüsselfrage ist, wie und wo Code-Zusammenführungen ablaufen, da dies wahrscheinlich den Weg des geringsten Widerstands bestimmen wird. Wie wird der Code zusammengeführt?
Wyatt Barnett
In der Regel wird eine Zusammenführung von einem persönlichen Zweig in einen Projekt- oder Feature-Zweig und anschließend in einen Stammzweig vorgenommen. Ich hatte nie zu viele Probleme mit Zusammenführungen (wir haben TortoiseSVN unter Win32 verwendet), obwohl wir nie zu lange (höchstens eine Iteration) liefen, ohne uns wieder in trunk zu integrieren. Wir haben den größten Teil unserer Arbeit sowieso im Kofferraum erledigt, obwohl das Ziel darin bestand, das Man-Management zu vereinfachen und nicht den Entwicklungsworkflow. (Ein Entwickler-Lead, viele unabhängig arbeitende Entwickler, sodass es für Entwickler einfacher ist, den Überblick zu behalten, was gerade geschah.)
William Payne
Ein wichtiger Punkt war die starke Abhängigkeit von Tests, die vom CI-System durchgeführt wurden, insbesondere auf der Ebene der Systemtests. Dies sollte dazu beitragen, das Vertrauen zu stärken, dass sich verschiedene Entwickler nicht gegenseitig stören, und eine Mentalität mit vielen kleinen Iterationen fördern. (Aufgrund des für die Durchführung der Systemtests erforderlichen rechenintensiven Aufwands gab es weniger Konflikte um Rechenressourcen, wenn die Mitarbeiter hauptsächlich am Rumpf arbeiteten.)
William Payne

Antworten:

10

Die Antwort von Spoike ist ausgezeichnet, aber ich denke, es gibt ein paar Dinge, die es wert sind, hinzugefügt zu werden, die zu groß für Kommentare sind.

Branchenorganisation

Mit Mercurial können Sie das gesamte erste Organigramm ignorieren. Wie Spoke sagt, hat jedes Repository einen eigenen Satz von Tags, Zweigen (benannt und anonym) und kann entsprechend den geschäftlichen Anforderungen organisiert werden.

Wenn bespokeProjectTwoeine spezielle Version der chartingBibliothek benötigt wird, können Sie verzweigen charting, die neuen Funktionen hinzufügen und diese in verwenden bespokeProjectTwo. Die neuen Einrichtungen (und ihre Fehler) würden nicht von anderen Projekten verwendet, die auf die Standardbibliothek verweisen würden charting. Wenn in der chartingHauptbibliothek Fehler behoben wurden, können Sie diese Änderungen in den Zweig einfügen. Wenn diese Einrichtungen auch für andere Projekte erforderlich sind, können Sie diese Projekte entweder dazu bringen, den speziellen Zweig zu verwenden, oder den Zweig in der Hauptlinie zusammenführen und den Zweig schließen.

Es steht auch nichts mehr im Wege, wenn Sie eine Richtlinie zum Strukturieren von Filialnamen haben, um bestimmte Funktionen wie Ihre AUTOMATION-Filialen bereitzustellen.

Verzeichnisorganisation

Es gibt keinen Grund, warum Sie Ihr Quellverzeichnis nicht genau so behalten können wie bei Mercurial. Der einzige Unterschied besteht darin, dass Sie mit Subversion ein einziges monolithisches (src)Repository haben, während Sie mit Mercurial besser in Repositorys aufteilen, die logisch gruppiert sind. Aus Ihrer Quelltextstruktur würde ich wahrscheinlich jedes der folgenden Elemente als einzelne Repositorys extrahieren:

src-+
      +-(developmentAutomation)
      +-libraries-+
      |           +-(log)
      |           +-(statistics)
      |           +-(charting)
      |           +-(distributedComputing)
      |           +-(widgets)
      +-productLines-+
      |              +-(flagshipProduct)
      |              +-(coolNewProduct)
      +-project-+
                +-bigImportantCustomer-+
                |                      +-(bespokeProjectOne)
                |                      +-(bespokeProjectTwo)
                +-anotherImportantCustomer-+
                                           +-(anotherBespokeProject)

Auf diese Weise kann jedes Produkt oder maßgeschneiderte Projekt bei jeder Überarbeitung eine beliebige Kombination von Bibliotheken verwenden. Schauen Sie sich die mercurial-Unter-Repositorys an, um auf einfache Weise zu verwalten, welche Bibliotheken für eine bestimmte Version eines Produkts oder Projekts verwendet werden.

Arbeitsablauf

Eine Alternative zum von Spoike vorgeschlagenen Workflow (der Entwickler greift auf das gesegnete Repo zurück, arbeitet lokal, gibt eine Abrufanforderung aus und schließlich zieht der Integrator diese Änderungen ab und führt sie zusammen) wäre die Verwendung des kontinuierlichen Integrationssystems als Vermittler.

Wie zuvor zieht der Entwickler aus dem gesegneten Repo und arbeitet lokal, aber wenn er fertig ist, zieht er erneut aus dem gesegneten Repo und verschmilzt sich, bevor er zu einem nicht gesegneten Repo wechselt. Alle Änderungen am nicht gesegneten Repo werden dann (entweder manuell oder automatisch) überprüft und nur dann in das gesegnete Repo verschoben, wenn sie genehmigt wurden.

Dies bedeutet, dass der Integrator nur eine Änderung akzeptieren oder ablehnen muss, nicht aber die Zusammenführung. Meiner Erfahrung nach ist es für den Entwickler, der den Code geschrieben hat, fast immer besser, die Zusammenführung durchzuführen, als für einen anderen.

Wie im Mercurial-Buch vorgeschlagen, können Hooks verwendet werden, um diesen Vorgang zu automatisieren:

Wenn jemand einen Änderungssatz auf den Server überträgt, von dem jeder abruft, testet der Server den Änderungssatz, bevor er ihn als permanent akzeptiert, und lehnt ihn ab, wenn er die Testsuite nicht besteht. Wenn Benutzer nur Änderungen von diesem Filterserver abrufen, wird sichergestellt, dass alle von ihnen abgerufenen Änderungen automatisch überprüft wurden.

Andere Probleme

Das Problem großer Testdatensätze kann auch dadurch gelöst werden, dass diese Testdaten in ein Quecksilber-Sub-Repository gestellt werden . Dadurch wird verhindert, dass das Code-Repository mit Testdaten überfüllt wird, während die Testdaten weiterhin unter Versionskontrolle bleiben.

Mark Booth
quelle
Nochmals eine ausgezeichnete und informative Antwort. Vielen Dank.
William Payne
RE: Filialorganisation. Ich stimme zu, dass das erste Organigramm gerne ignoriert werden kann. Es hat den Workflow ohnehin nicht besonders gut kommuniziert und bot daher keinen wirklichen Nutzen, der über die Konvention der Verstärkung hinausging. Ich möchte es jedoch durch etwas ersetzen, das einen (möglichst einfachen) Workflow stark kommuniziert und zu häufigen Commits ermutigt. Vielleicht würde es das tun, wenn man den Hauptzweig "Stamm / Entwicklung" "täglich" nennt?
William Payne
RE: Verzeichnisorganisation. Ich benutzte die Organisation des Quellverzeichnisses als unterschwelliges Kommunikationsmittel. Auferlegung einer impliziten Struktur für die Organisation des Codes (und damit für das gesamte Unternehmen). Ich fange an zu verstehen, dass Mercurial sehr flexibel eingesetzt wird. Aber ich möchte wirklich einen Teil dieser Flexibilität einschränken, um eine Struktur für die Art und Weise festzulegen, in der die Leute über das Geschäft nachdenken, indem eine Struktur für die Art und Weise festgelegt wird, in der ihre Dokumente auf ihren Arbeitsstationen und in unseren Netzwerkspeicherbereichen organisiert sind. (Mehr Unternehmenskommunikation als Technologie.)
William Payne
RE: Workflow. Ich denke, dass der einfachste Workflow darin besteht, aus einem "täglichen" Repository zu ziehen, es lokal zu bearbeiten und dann (häufig) in das "tägliche" Repository zurückzukehren und statische Analysen, Rauch- und Regressionstests über das CI-System zu starten. Ich bin froh, dass das Hauptrepo "kaputt" ist, solange ich davon weiß und es schnell wieder repariert wird. In der Tat denke ich darüber nach, das Commit für das "tägliche" Repo zur einzigen Möglichkeit zu machen, die man kompilieren und erstellen kann, um häufige Commits und eine gute Testabdeckung zu fördern. (Weit wichtiger als die Fähigkeit, isoliert zu arbeiten, IMHO).
William Payne
@ WilliamPayne - Danke. Während Mercurial flexibel ist, können Sie mit geeigneten Repositorys, Zweigen und Hooks beliebige Einschränkungen auf Organisations- oder Repository-Ebene erstellen. Persönlich würde ich einfach mit organisatorischen Kontrollen und einigen CI-Hooks beginnen und diese Kontrollen in Zukunft erweitern, wenn deren Bedarf offensichtlich wird. Ein umsichtiger Einsatz von Sub-Repos kann beispielsweise dazu führen, dass Personen Dinge lokal in der gleichen Struktur wie auf dem Server auschecken, z. B. mit productLinesoder bigImportantCustomerals Super-Repos.
Mark Booth
9

Okay, versuche das einfach zu beantworten.

Was du wissen musst

Das erste, was Sie wissen müssen: Mercurial ist eine verteilte Versionskontrolle und verfügt über einige Eigenschaften, die Sie kennen sollten.

  • Die Quelle stammt aus einem Repository, in das das Repository geklont werden kann. Alle geklonten Repositorys können durch Synchronisierung Code miteinander teilen (mit Pull- und Push-Befehlen, auf die nur eingeschränkt zugegriffen werden kann).
  • Jeder Benutzer, der eine Kopie des Codes hat, hat einen Klon des Repositorys. Wenn sie verzweigen möchten, können sie dies in ihrem lokalen Klon tun. Das heißt, Sie müssen nicht festlegen, wie jeder Benutzer verzweigen soll. Sie können dies für sich selbst tun.
  • Tags werden in mercurial durch ein Commit erstellt (das entspricht den harten Tags in git). Dies bedeutet, dass Sie in Ihrer Repository-Struktur kein Verzeichnis für Tags benötigen.
  • Das übliche Modell, mit dem die Leute in DVCS (das in Github und Bitbucket verwendet wird) arbeiten, ist es, es semi-zentral zu machen.

    Jeder Benutzer verfügt über ein öffentliches Repository (in einer Freigabe oder auf einem sicheren Server) und ein privates Repository (auf seinen eigenen Arbeitsstationen). Sie sind beide Klone des "gesegneten" Repository eines Integrators. Wann immer sie sich bereit fühlen, ihren Code zu veröffentlichen, können sie die Änderungen in ihr öffentliches Repository übertragen. Ein Integrator kann dann auswählen, welche Benutzer Code in das "gesegnete" Repository ziehen sollen.

    Wenn der Integrator den Code eines Benutzers nicht einfach zusammenführen kann, werden die Änderungen verworfen, und es liegt an diesem bestimmten Benutzer, sein Repository zu aktualisieren und die Zusammenführung selbst zu beheben. Es ist normalerweise nicht so schwierig, wenn Sie häufig zusammenführen (da weniger Code zusammengeführt werden muss), und normalerweise sollte der Benutzer wissen, was bei der Zusammenführung schief gelaufen ist.

Projektarchiv-pro-Projekt-Setup

So ist die übliche Einstellung, dass es für jedes Projekt die folgenden gibt:

  • Ein öffentliches schreibgeschütztes Repository, für das der Integrator verantwortlich ist. Es ist "gesegnet".

    Dh alle Benutzer können Inhalte abrufen / abrufen, haben jedoch keinen Zugriff darauf.

  • Jeder Benutzer kann einen eigenen öffentlichen Klon des Repositorys haben.

    Am einfachsten lässt es sich auf einem freigegebenen Laufwerk einrichten (auch wenn Sie eventuell ein Hosting wie bitbucket in Betracht ziehen). Der Integrator empfängt Pull-Anforderungen von den Benutzern und versucht, den neuen Code aus diesen Repositorys abzurufen. Wenn Zusammenführungen problemlos durchgeführt werden, werden sie in das schreibgeschützte Repository gestellt. Ist dies nicht der Fall, werden Benutzer aufgefordert, die Zusammenführungskonflikte zu beheben, die durch das lokale Aktualisieren und Zusammenführen entstehen.

  • Jeder Benutzer kann seine eigenen privaten Klone des Repositorys haben.

    Es hat sich bewährt, von ihrem öffentlichen Klon abzurufen, aber es spielt keine Rolle, ob sie von ihrem öffentlichen Klon oder dem des Integrators abrufen. Alle Festschreibungen sind eindeutig identifizierbar, so dass das Zusammenführen von Festschreibungen, die Sie in der Öffentlichkeit vergessen haben, relativ einfach zu beheben ist (indem Sie die Änderungen von privat an öffentlich weitergeben, werden auch die Änderungen des Integrators automatisch übernommen).

Organisation des Quellcodes

Wie man die Projektquelle selbst arrangiert, muss man sich überlegen. Wenn ein Artefakt einer Quellcodeverwaltung unterzogen werden muss, versetzen Sie es in die Quellcodeverwaltung. Persönlich mag ich es nicht, Artefakte einzuchecken, die während des Builds oder der Laufzeit erstellt wurden (aufgrund des hohen Risikos von Zusammenführungskonflikten bei solchen Artefakten), wie z. B. Binärdateien oder Protokolldateien.

Sie können auch die Konfiguration einchecken, sofern dies Entwicklern den Einstieg erleichtert und die Konfiguration für Releases oder Live- / Produktionsumgebungen (z. B. App- / Webserver-Einstellungen) nicht beeinträchtigt. Dies führt zu dem Gedanken, dass, wenn die Konfiguration, die Sie vorgenommen haben, die Entwickler ernsthaft daran hindert, innerhalb von fünf Minuten nach dem Auschecken des Codes zu beginnen, dieser überarbeitet werden muss. Eine weitere Anforderung ist, dass es für die Entwickler verdammt schwierig sein sollte, die Release- oder Live- / Produktionsumgebung durcheinander zu bringen.

Sie erwähnen, dass Sie Testdaten haben, die an eine Version des Codes gebunden werden müssen. Das ist etwas kniffliger, da DVCS-Systeme wie Mercurial und Git dazu neigen, beim Einchecken von riesigen Daten langsam zu werden. Nach meiner Erfahrung wird es nach 5 GB Binärdateien wirklich unerträglich (Ihre Laufleistung kann variieren, Sie sollten also testen, wie es für Sie funktioniert). Ich würde jedoch empfehlen, dass Sie generierte Daten in einem eigenen Repository ablegen und sie beim Einchecken von Ihrem Testsystem entsprechend kennzeichnen lassen (und / oder Textdateien für dieselben Metadatenzwecke erstellen).

Ich hoffe das alles macht Sinn. Bitte kommentieren Sie unten, wenn ich ein Detail verpasst habe oder wenn etwas näher erläutert werden muss, und ich werde versuchen, es zu bearbeiten.

Spoike
quelle
+1 für eine sehr schöne Antwort mit mehreren sehr nützlichen Punkten. Als Antwort auf den ersten Abschnitt Ihrer Antwort hatte ich nicht begriffen, wie wichtig es ist, dass jeder Benutzer ein eigenes öffentliches Repository hat. Vielleicht muss ich mehr darüber nachdenken, wie Peer-to-Peer-Workflows organisiert werden könnten.
William Payne
Als Antwort auf den zweiten Abschnitt Ihrer Antwort ist es (meiner Meinung nach) der springende Punkt, ein einziges Repository für die gesamte Organisation zu haben, um ein gemeinsames mentales Bild für die Struktur der Arbeit zu erstellen und das Auffinden von Komponenten zu erleichtern, die dies können wiederverwendet werden. (Sehr viel eher die Kathedrale als der Basar, aber das ist die Umgebung, in der ich arbeite). Ich würde wirklich gerne wissen, wie man mit einem DCVS den gleichen Sinn für strukturierte Organisation (Ablagesystem) erreicht.
William Payne
Als Antwort auf den dritten Abschnitt Ihrer Antwort: Ich stimme voll und ganz zu, dass das Versionsverwaltungssystem für Quelldokumente vorgesehen ist und abgeleitete Artefakte nicht dorthin gehören. Ich stimme auch zu, dass es unpraktisch ist, große Binärdateien jeglicher Art in VCS zu speichern. Ich glaube jedoch, dass Sie große Binärdateien an einem vereinbarten Netzwerkstandort mit einem definierten Namen speichern und im VCS darauf verweisen können. Beispielsweise können die Erstellungsumgebungen als benannte VM-Datenträgerabbilder gespeichert und in den verschiedenen Erstellungsskripten referenziert werden. (zB: baue mich auf build_env_A). Gleiches gilt für Testdaten.
William Payne
In der Vergangenheit habe ich eine Hierarchie von Verzeichnissen auf einem Netzlaufwerk verwendet, bei der die Verzeichnisnamen von der Subversion-Versionsnummer + dem Hash des Verzweigungsorts abgeleitet wurden, um Zwischendateien und Testergebnisse an bestimmte Versionen zu binden. Dies bedeutet, dass wir die Rückverfolgbarkeit haben, ohne abgeleitete Dateien in der Versionskontrolle speichern zu müssen.
William Payne