Struttura del repository mercuriale con comunicazioni aziendali pesanti, requisiti di gestione della configurazione e test


16

Sono ancora un altro utente di Subversion che fatica a rieducare me stesso nel Tao del controllo della versione distribuita.

Quando utilizzavo Subversion, ero un grande fan dell'approccio del progetto minore e, con la maggior parte dei miei ex datori di lavoro, strutturavamo i nostri repository; tag e trunk come segue:

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

All'interno dello stesso albero dei sorgenti, useremmo (qualcosa di simile) la seguente struttura:

  (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

L'idea era (ed è tuttora) di utilizzare la struttura del repository per aiutare a strutturare la comunicazione tra il team di ingegneri; la parte del business rivolta al cliente e varie altre parti interessate ed esperti di dominio.

In altre parole: i documenti di origine che si trovano in una delle directory del "progetto" vengono utilizzati (e guadagnano) una sola volta. I documenti che si trovano in una delle directory "productLines" guadagnano denaro quante volte viene venduto un prodotto di quella particolare linea. I documenti che si trovano in una delle directory delle "biblioteche" guadagnano denaro tutte le volte che viene venduto qualsiasi prodotto che li utilizza.

Rende esplicita la nozione di ammortamento dei costi e aiuta a costruire il supporto per il riutilizzo dei documenti di origine in tutta l'azienda.

Significa anche che esiste una struttura comune su cui possono operare i nostri strumenti di automazione della costruzione. (I nostri script di compilazione percorrono l'albero dei sorgenti alla ricerca di cartelle "build" all'interno delle quali trovano i file di configurazione che specificano come costruire ciascun componente; un processo simile si verifica per la generazione e il test della documentazione).

Significativamente, i prodotti su cui lavoro in genere impiegano molto tempo per eseguire test di misurazione e caratterizzazione delle prestazioni; dalle 20 alle 200 ore; generazione da qualche parte tra diversi GB a diversi TB di risultati di test elaborati / dati intermedi (che devono essere memorizzati e collegati a una particolare configurazione del sistema in modo da poter misurare il miglioramento delle prestazioni nel tempo). Questo problema rende la gestione della configurazione una considerazione importante e impone anche alcuni requisiti per la centralizzazione, poiché in genere le risorse computazionali necessarie per eseguire i test di misurazione e caratterizzazione delle prestazioni sono limitate; (un piccolo gruppo di 64-128 core).

Come ultima nota; il sistema di integrazione continua sa che deve innescare una build; analisi statica; test del fumo e test dell'unità vengono eseguiti ogni volta che viene modificato il tronco, ogni volta che viene modificato un ramo "tag" e ogni volta che viene modificato un ramo "AUTOMATICO". In questo modo, i singoli sviluppatori possono utilizzare il sistema CI con i loro rami personali, una capacità importante, IMHO.

Ora, ecco la mia domanda: come posso replicare tutto quanto sopra (e migliorarlo, se possibile), con Mercurial.

--modificare:

La mia attuale linea di pensiero è quella di utilizzare un repository Subversion centrale, per definire la struttura generale, ma per consentire l'uso di hg come client in modo che gli sviluppatori possano disporre di repository disponibili localmente.


1
Wow. Una buona risposta a questo sarà un saggio molto lungo credo.
Ed James,

Penso che la domanda chiave sia come e dove stanno andando le fusioni di codice poiché ciò probabilmente definirà il percorso di minor resistenza. Quindi, come viene unito il codice?
Wyatt Barnett,

In genere, un'unione potrebbe provenire da un ramo personale in un ramo di progetto o di funzione e quindi nel trunk. Non ho mai avuto troppe difficoltà con le fusioni (stavamo usando TortoiseSVN su Win32), anche se non abbiamo mai funzionato per troppo tempo (una iterazione al massimo) senza integrarle di nuovo nel trunk. Tendevamo comunque a svolgere gran parte del nostro lavoro nel bagagliaio, sebbene l'obiettivo fosse semplificare la gestione dell'uomo piuttosto che il flusso di lavoro di sviluppo. (Un dev-lead, molti sviluppatori che lavorano in modo indipendente, quindi avere tutto nel bagagliaio ha reso più facile sul dev-lead tenere traccia di ciò che stava accadendo.)
William Payne,

Un punto chiave era la forte dipendenza dai test condotti dal sistema CI, in particolare a livello di test di sistema. Questo per aiutare a costruire la fiducia che i diversi sviluppatori non interferivano l'uno con l'altro e per promuovere una mentalità da molte piccole iterazioni. (Inoltre, il pesante sollevamento computazionale necessario per eseguire i test di sistema ha comportato una minore contesa per le risorse computazionali se le persone lavoravano principalmente sul tronco).
William Payne,

Risposte:


10

La risposta di Spoike è eccellente, ma penso che varrebbe la pena aggiungere altre che sono troppo grandi per i commenti.

Organizzazione delle filiali

Con Mercurial puoi tranquillamente ignorare l'intero tuo primo organigramma. Come dice Spoke, ogni repository ha il proprio set di tag, rami (nominati e anonimi) e può essere organizzato in base alle esigenze aziendali.

Se hai bespokeProjectTwobisogno di una versione speciale della chartinglibreria, allora dovresti ramificarti charting, aggiungere le nuove strutture e usarlo in bespokeProjectTwo. Le nuove strutture (e i loro bug) non verrebbero utilizzate da altri progetti che farebbero riferimento alla chartinglibreria standard . Se nella chartinglibreria principale sono stati corretti dei bug, è possibile unire tali modifiche nel ramo. Se anche altri progetti necessitavano di queste strutture, è possibile ottenere quei progetti per utilizzare il ramo speciale o unire il ramo nella linea principale e chiudere il ramo.

Inoltre, non c'è nulla che ti impedisca di avere una politica per strutturare i nomi delle filiali per fornire servizi specifici come le tue filiali di AUTOMAZIONE.

Organizzazione delle directory

Non vi è alcun motivo per cui non è possibile mantenere la directory di origine esattamente come è con Mercurial. L'unica differenza è che mentre con Subversion hai un unico (src)repository monolitico , con Mercurial stai meglio suddividendolo in repository che sono raggruppati logicamente. Dalla struttura dell'albero di origine, probabilmente estrarrei ciascuno dei seguenti come singoli repository:

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

Ciò consente a qualsiasi prodotto o progetto su misura di utilizzare qualsiasi combinazione di librerie, a qualsiasi revisione. Dai un'occhiata ai sottopository mercuriali per un modo semplice per gestire le librerie utilizzate per una determinata versione di un prodotto o progetto.

Flusso di lavoro

Un'alternativa al flusso di lavoro suggerito da Spoike (lo sviluppatore estrae da un repository benedetto, lavora localmente, emette una richiesta pull e infine l'integratore inserisce tali modifiche e le unisce) sarebbe utilizzare il sistema di integrazione continua come intermediario.

Come in precedenza, lo sviluppatore estrae dal repository benedetto e lavora localmente, ma una volta terminato, estrae nuovamente dal repository benedetto e si fondono prima di passare a un repository senza licenza. Eventuali modifiche al repository senza licenza vengono quindi riviste (manualmente o automaticamente) e spostate nel repository benedetto solo se approvate.

Ciò significa che l'integratore ha accettato o rifiutato solo una modifica, non l'unione. Nella mia esperienza, è quasi sempre meglio per lo sviluppatore che ha scritto il codice eseguire l'unione che per qualcun altro.

Come suggerito nel libro mercuriale, i ganci possono essere utilizzati per automatizzare questa procedura:

Quando qualcuno invia un changeset al server da cui tutti eseguono il pull, il server testerà il changeset prima di accettarlo come permanente e lo rifiuterà se non riesce a passare la suite di test. Se le persone estraggono solo le modifiche da questo server di filtraggio, ciò servirà a garantire che tutte le modifiche che le persone tirano siano state verificate automaticamente.

Altri problemi

Il problema di grandi set di dati di test può anche essere risolto inserendo tali dati di test in un sotto-repository mercuriale . Ciò eviterà che il repository di codice si gonfi di dati di test, mantenendo comunque i dati di test sotto controllo di revisione.


Ancora una volta, un'altra risposta eccellente e istruttiva. Grazie.
William Payne,

RE: Organizzazione delle filiali. Concordo sul fatto che il primo organigramma può essere felicemente ignorato. In ogni caso, non comunicava particolarmente bene il flusso di lavoro, quindi non forniva alcuna reale utilità oltre al rafforzamento della convenzione. Vorrei sostituirlo, tuttavia, con qualcosa che comunica fortemente un flusso di lavoro (il più semplice possibile) e incoraggia impegni frequenti. Forse chiamare il "ramo / sviluppo" principale "quotidiano" lo farebbe?
William Payne,

RE: Organizzazione directory. Stavo usando l'organizzazione della directory di origine come mezzo di comunicazione subliminale; imporre una struttura implicita sull'organizzazione del codice (e attraverso quella sull'intera impresa). Sto cominciando a capire che Mercurial tende ad essere usato in modo molto flessibile; ma voglio davvero limitare un po 'di quella flessibilità per imporre una struttura sul modo in cui le persone pensano al business imponendo una struttura sul modo in cui i loro documenti sono organizzati sulle loro stazioni di lavoro e sulle nostre aree di archiviazione di rete. (Più comunicazioni aziendali che tecnologia.)
William Payne,

RE: flusso di lavoro. Penso che il flusso di lavoro più semplice sarebbe quello di estrarre da un repository "quotidiano", lavorare su di esso localmente, quindi (frequentemente) tornare al repository "quotidiano", dando il via a analisi statiche, test del fumo e test di regressione tramite il sistema CI. Sono felice che il repository principale sia "rotto", purché ne sia a conoscenza, e purché venga riparato rapidamente. In effetti, sto prendendo in considerazione l'idea di impegnarmi nel repo "giornaliero" l' unico modo per compilare e costruire, per incoraggiare impegni frequenti e una buona copertura dei test. (Molto più importante della capacità di lavorare in isolamento, IMHO).
William Payne,

@WilliamPayne - Grazie. Sebbene Mercurial sia flessibile, con repository, filiali e hook appropriati, puoi creare qualsiasi restrizione desideri, a livello organizzativo o di repository. Personalmente, inizierei semplicemente con i controlli organizzativi e alcuni hook di CI, estendendoli in futuro man mano che le loro esigenze diventano evidenti. Inoltre, un uso oculato dei repository potrebbe, ad esempio, incoraggiare le persone a controllare le cose localmente nella stessa struttura presente sul server, ad esempio disponendo productLineso bigImportantCustomercome super repository.
Mark Booth,

9

Ok, provando a rispondere semplicemente.

Cosa hai bisogno di sapere

Prima cosa che devi sapere: Mercurial è il controllo della versione distribuita e ha alcune proprietà che dovresti conoscere elencate di seguito.

  • La fonte proviene da un repository, in cui tale repository può essere clonato. Tutti i repository clonati possono condividere il codice tra loro tramite la sincronizzazione (con comandi pull e push, a cui è possibile limitare l'accesso).
  • Ogni utente che ha una copia del codice, ha un clone del repository. Se vogliono ramificarsi, possono farlo nel loro clone locale. Ciò significa che non è necessario organizzare il modo in cui ogni utente dovrebbe diramarsi. Possono farlo da soli.
  • I tag sono creati in mercurial da un commit (che è lo stesso dei tag hard in git). Ciò significa che non è necessaria una directory all'interno della struttura del repository per i tag.
  • Il solito modello con cui le persone lavorano in DVCS (che viene utilizzato in github e bitbucket) è quello di farlo semi-centralizzato.

    Ogni utente ha un repository pubblico (in alcune condivisioni o su un server sicuro) e un repository privato (nelle proprie workstation). Sono entrambi cloni del repository "benedetto" di un integratore. Ogni volta che si sentono pronti a pubblicare il loro codice, possono trasferire le modifiche al loro archivio pubblico. Un integratore può quindi scegliere quali utenti estrarre il codice nel repository "benedetto".

    Se l'integratore non riesce a unire facilmente il codice di alcuni utenti, le modifiche vengono rifiutate e spetta a quel particolare utente aggiornare il proprio repository e correggere l'unione stessa. Di solito non è così difficile se ti unisci spesso (poiché è meno il codice che deve essere unito) e di solito quell'utente dovrebbe sapere cosa è andato storto con l'unione.

Installazione dei repository per progetto

Quindi il solito set up è che per ogni progetto c'è il seguente:

  • Un repository di sola lettura pubblico di cui è responsabile l'integratore. È "benedetto".

    Vale a dire che tutti gli utenti possono estrarre / recuperare i contenuti ma non hanno accesso per spingerli.

  • Ogni utente può avere il proprio clone pubblico del repository.

    La configurazione più semplice viene messa in un'unità di condivisione (anche se potresti considerare l'hosting come bitbucket). L'integratore riceve le richieste pull dagli utenti e tenta di estrarre il nuovo codice da questi repository. Quando le fusioni vengono eseguite senza intoppi, vengono inserite nel repository di sola lettura. In caso contrario, agli utenti viene chiesto di correggere i conflitti di unione che si verificano aggiornando e fondendo i dati localmente.

  • Ogni utente può avere i propri cloni privati ​​del repository.

    La buona pratica è estrarre dal loro clone pubblico, ma non importa se attingono dal loro pubblico o da quello dell'integratore. Tutti i commit sono identificabili in modo univoco, quindi la fusione dei commit che hai dimenticato di recuperare in pubblico è relativamente facile da risolvere (spingendo le modifiche dal privato al pubblico, ottiene automaticamente anche le modifiche dell'integratore).

Organizzazione del codice sorgente

Come su come organizzare la fonte del progetto stesso è qualcosa su cui devi riflettere. Se un artefatto deve essere controllato dal codice sorgente, mettilo nel controllo codice sorgente. Personalmente non mi piace l'idea di archiviare artefatti creati dalla build o dal runtime (a causa dell'elevato rischio di unire conflitti su questo tipo di artefatti) come file binari o file di registro.

Puoi anche effettuare il check-in della configurazione, a condizione che rendano facile per gli sviluppatori andare avanti e non rovinino la configurazione per le versioni o l'ambiente live / di produzione (come le impostazioni dell'app / web server). Questo porta all'idea che se la configurazione che hai ostacola seriamente gli sviluppatori per iniziare entro cinque minuti dopo aver verificato il codice, deve essere riformattato. Un altro requisito è che dovrebbe essere difficile per gli sviluppatori confondere il rilascio o l'ambiente live / di produzione.

Dici che hai dei dati di test che devono essere collegati ad alcune versioni del codice. Ora questo è un po 'più complicato perché i sistemi DVCS come Mercurial e Git hanno la tendenza a rallentare quando si eseguono il check-in dei dati ENORMI. Nella mia esperienza diventa davvero insopportabile dopo 5 GB di file binari (il tuo chilometraggio può variare, quindi dovresti provare come funziona per te). Raccomanderei comunque di inserire i dati generati nel proprio repository e di fare in modo che il sistema di test li tagghi in modo appropriato al momento del check-in (e / o creare file di testo per gli stessi scopi dei metadati).

Spero che tutto ciò abbia un senso. Commenta di seguito se ho perso alcuni dettagli o se qualcosa deve essere ulteriormente spiegato e proverò a modificarlo.


+1 per una risposta molto bella con diversi punti molto utili. In risposta alla prima sezione della tua risposta, non avevo capito il significato di ogni utente che aveva il proprio repository pubblico. Forse devo pensare di più a come organizzare i flussi di lavoro peer-to-peer.
William Payne,

In risposta alla seconda sezione della tua risposta, il punto (nella mia mente) di avere un unico repository per l'intera organizzazione è creare un'immagine mentale condivisa per come è strutturato il lavoro e per facilitare la ricerca di componenti che possono essere riutilizzato. (Molto la Cattedrale piuttosto che il Bazar, ma questo è l'ambiente in cui lavoro). Mi piacerebbe davvero sapere come ottenere lo stesso senso di organizzazione strutturata (sistema di archiviazione) con un DCVS.
William Payne,

In risposta alla terza sezione della tua risposta: concordo pienamente che il sistema di controllo del codice sorgente è per i documenti sorgente e che i manufatti derivati ​​non vi appartengono. Concordo anche sul fatto che non è pratico archiviare file binari di grandi dimensioni di qualsiasi descrizione in VCS. Ritengo, tuttavia, che sia possibile archiviare file binari di grandi dimensioni in un percorso di rete concordato, con un nome definito, e fare riferimento a essi all'interno del VCS. Ad esempio, gli ambienti di compilazione possono essere archiviati come immagini del disco VM denominate e referenziati dai vari script di compilazione. (es: build me su build_env_A). Lo stesso vale per i dati di test.
William Payne,

In passato, ho usato una gerarchia di directory su un'unità di rete, in cui i nomi delle directory sono derivati ​​dal numero di revisione della sovversione + hash della posizione del ramo per collegare i file intermedi e i risultati dei test a revisioni particolari. Ciò significa che abbiamo tracciabilità senza la necessità di archiviare i file derivati ​​nel controllo della versione.
William Payne,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.