Organizzazione dei repository Git con sottomoduli nidificati comuni


50

Sono un grande fan dei sottomoduli Git . Mi piace essere in grado di tracciare una dipendenza insieme alla sua versione, in modo da poter eseguire il rollback a una versione precedente del progetto e avere la versione corrispondente della dipendenza da costruire in modo sicuro e pulito. Inoltre, è più facile rilasciare le nostre biblioteche come progetti open source poiché la cronologia delle biblioteche è separata da quella delle applicazioni che dipendono da esse (e che non saranno open source).

Sto impostando il flusso di lavoro per più progetti al lavoro e mi chiedevo come sarebbe se avessimo adottato questo approccio un po 'estremo invece di avere un singolo progetto monolitico. Mi sono reso rapidamente conto che esiste una potenziale lattina di worm che utilizza davvero i sottomoduli.

Supponendo una coppia di applicazioni: studioe player, e librerie dipendenti core, graphe network, se le dipendenze sono i seguenti:

  • core è autonomo
  • graphdipende da core(sottomodulo at ./libs/core)
  • networkdipende da core(sottomodulo at ./libs/core)
  • studiodipende da graphe network(sottomoduli at ./libs/graphe ./libs/network)
  • playerdipende da graphe network(sottomoduli at ./libs/graphe ./libs/network)

Supponiamo che stiamo usando CMake e che ciascuno di questi progetti abbia unit test e tutte le opere. Ogni progetto (incluso studioe player) deve poter essere compilato autonomamente per eseguire metriche di codice, unit test, ecc.

Il fatto è, ricorsivo git submodule fetch, quindi ottieni la seguente struttura di directory:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/graph/
studio/libs/graph/libs/         (sub-module depth: 2)
studio/libs/graph/libs/core/
studio/libs/network/
studio/libs/network/libs/       (sub-module depth: 2)
studio/libs/network/libs/core/

Si noti che coreviene clonato due volte nel studioprogetto. A parte questo spreco di spazio su disco, ho un problema di sistema di compilazione perché sto costruendo coredue volte e potenzialmente ottengo due diverse versioni di core.

Domanda

Come organizzare i sottomoduli in modo da ottenere la dipendenza con versione e la build autonoma senza ottenere più copie dei sottomoduli nidificati comuni?

Possibile soluzione

Se la dipendenza dalla libreria è in qualche modo un suggerimento (vale a dire in un modo "noto per funzionare con la versione X" o "solo la versione X è ufficialmente supportata") e le potenziali applicazioni o librerie dipendenti sono responsabili della costruzione con qualsiasi versione che preferiscono, allora Potrei immaginare il seguente scenario:

  • Avere il sistema di compilazione per graphe networkdire loro dove trovare core(ad esempio tramite un percorso di inclusione del compilatore). Definire due target di build, "standalone" e "dipendenza", in cui "standalone" si basa su "dipendenza" e aggiunge il percorso di inclusione per puntare al coresottomodulo locale .
  • Introdurre una dipendenza aggiuntiva: studioattiva core. Quindi, studiocrea core, imposta il percorso di inclusione sulla propria copia del coresottomodulo, quindi crea graphe networkin modalità "dipendenza".

La struttura delle cartelle risultante è simile a:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/core/
studio/libs/graph/
studio/libs/graph/libs/         (empty folder, sub-modules not fetched)
studio/libs/network/
studio/libs/network/libs/       (empty folder, sub-modules not fetched)

Tuttavia, ciò richiede un po 'di magia per il sistema di compilazione (sono abbastanza sicuro che questo possa essere fatto con CMake) e un po' di lavoro manuale da parte degli aggiornamenti della versione (l'aggiornamento graphpotrebbe anche richiedere l'aggiornamento coree networkottenere una versione compatibile di corein tutti i progetti) .

Qualche idea su questo?


Nota che questo problema non è specifico di cmake: esiste per qualsiasi sistema di compilazione, incluso nessun sistema! (vale a dire quando si prevede che il super-progetto aggiunga solo le fonti della libreria; che include le librerie solo di intestazione)
MM

Risposte:


5

Sono in ritardo a questa festa, ma la tua domanda non sembra ancora avere una risposta completa, ed è un successo piuttosto rilevante da parte di Google.

Ho lo stesso identico problema con C ++ / CMake / Git / Submodules e ho un problema simile con MATLAB / Git / Submodules, che ottiene qualche stranezza in più perché MATLAB non è compilato. Mi sono imbattuto recentemente in questo video , che sembra proporre una "soluzione". Non mi piace la soluzione, perché essenzialmente significa buttare via i sottomoduli, ma elimina il problema. È proprio come raccomanda @errordeveloper. Ogni progetto non ha sottomoduli. Per costruire un progetto, crea un super-progetto per costruirlo e includilo come fratello delle sue dipendenze.

Quindi il tuo progetto di sviluppo graphpotrebbe apparire come:

buildgraph/graph
buildgraph/core

e quindi il tuo progetto per studio potrebbe essere:

buildstudio/studio
buildstudio/graph
buildstudio/network
buildstudio/core

I super-progetti sono solo uno dei principali CMakeLists.txte un mucchio di sottomoduli. Ma nessuno dei progetti ha alcun sottomodulo.

L'unico costo che vedo in questo approccio è la proliferazione di banali "super-progetti" che sono dedicati alla costruzione dei tuoi veri progetti. E se qualcuno ottiene uno dei tuoi progetti, non c'è modo semplice per dire senza trovare anche il super-progetto, quali sono le sue dipendenze. Questo potrebbe renderlo davvero brutto su Github, per esempio.


1

Suppongo che quando si integrano entrambi graphe i networksottomoduli studio, è sempre necessario avere la stessa versione di corein un determinato momento nella storia di studio. Vorrei simulare il studio/libs/coresottomodulo in studio/libs/{graph,network}/libs.

Aggiornare:

Ho creato più repository con le dipendenze che hai dichiarato:

./core      <--- (v2)
./graph
./graph/libs
./graph/libs/core  <--- (v2)
./graph/.gitmodules
./network
./network/libs
./network/libs/core  <--- (v1)
./network/.gitmodules
./studio
./studio/libs
./studio/libs/graph
./studio/libs/graph/libs
./studio/libs/graph/libs/core <--- (v1)
./studio/libs/graph/.gitmodules
./studio/libs/network
./studio/libs/network/libs
./studio/libs/network/libs/core  <--- (v1)
./studio/libs/network/.gitmodules
./studio/studio
./studio/.gitmodules

v1e v2sono due diverse versioni di core. graphgestisce la versione 2, mentre networknecessita di un po 'di lavoro ed è bloccato alla versione 1. In studio, le versioni locali incorporate di coreentrambi i punti v1per avere un programma di lavoro. Ora, a parte la prospettiva di costruzione, tutto funziona bene con i sottomoduli.

Ora posso rimuovere la seguente directory:

./studio/libs/network/libs/core

E sostituiscilo con un link simbolico:

./studio/libs/network/libs/core@ -> ../../graph/libs/core/

Commetto localmente questo cambiamento e perdo la possibilità di avere due versioni separate di coreinside studio, ma costruisco solo coreuna volta. Quando sono pronto per l'aggiornamento v2, posso fare:

 git submodule update # (--rebase ?)

... all'interno di studio / libs / network.


L'idea del collegamento simbolico mi è venuta in mente, ma non è una soluzione. Se si collega graph/libs/coredall'esterno, non si utilizza il sottomodulo. Se si collega da studio/libs/coreuna delle librerie del sottomodulo, quale scegliere, grapho network? Inoltre, cosa succede quando è profondo tre o più strati? Infine, cosa succede se corepuò essere una serie di revisioni. Non è ovvio che tu voglia collegarti a entrambe le versioni e coreche stai usando. graphnetwork
André Caron,

"Quale scegli ?" : coresarebbe un sottomodulo recuperato dalla corelibreria originale , aggiornato a una versione compatibile con entrambi graphe network(è necessario decidere quale è buono). I collegamenti simbolici verrebbero aggiunti in locale graphe networksottomoduli (non recuperati).
coredump,

1
I collegamenti simbolici che proponi di aggiungere graphe che networkfaresti riferimento al di fuori del proprio repository (ad es. Altrove nel studioprogetto). Come fanno a sapere quando utilizzare il proprio sottomodulo rispetto a quando utilizzare il collegamento simbolico? Forse dovresti aggiungere un esempio per dimostrare il tuo modo di pensare.
André Caron,

0

Lo appiattirei per avere una profondità del sotto-modulo di uno solo e avere un repository che terrebbe tutti i moduli come sotto-moduli e nient'altro a parte README e gli script di build. Ci sarebbe uno script di build separato per ciascuno dei pacchetti che collega le sue dipendenze. Altrimenti puoi avere un repository separato per un pacchetto.


1
Non sono sicuro che questo fosse chiaro nel mio post, ma ho più applicazioni che dipendono dalle stesse librerie e non voglio duplicare gli script di build per le librerie tra le applicazioni.
André Caron,

3
Dovresti elaborare la tua risposta per dimostrare come affronta le diverse questioni. Non mi è chiaro esattamente come colleghi le dipendenze dato che, a seconda del contesto, le librerie dipendenti non si trovano nella stessa posizione.
André Caron,

0

Non vorrei usare i sottomoduli.

È allettante, proprio come in passato con svn-externals. Tuttavia, puoi essere sicuro che tutti quei progetti che colleghi siano ancora nello stesso posto tra un anno? Che ne dici di cinque?

Pertanto, sto semplicemente copiando tutte le dipendenze richieste nel mio progetto. Ciò significa che finché il mio repository è valido, posso verificare lo stato esatto.

Fondamentalmente, ho una struttura di cartelle come segue:

myproject/... [sources etc]
ext/ [third-party dependencies]


e.g. ext/boost, ext/cppunit

Anche se questo non è molto carino dal punto di vista dello spazio su disco, apprezzo la garanzia di poter verificare ogni stato registrato fino a quando il repository sarà disponibile molto più in alto.

Inoltre, ci sono un sacco di problemi con i sottomoduli come descritto qui


Sono sicuro che si trovano nella posizione giusta perché li sto mantenendo tutti :-) Inoltre, fai attenzione a copiare i progetti a causa delle condizioni di ridistribuzione.
André Caron,

OK, questo riduce il problema. E le licenze: Sì, devi stare attento, ma questo è un problema completamente diverso.
Wilbert,

0

Di fronte esattamente allo stesso problema qui. Una delle soluzioni potrebbe essere quella di avere un po 'di pronti contro termine libsche terrebbe core, network, graphcome sottomoduli ea soli CMakeLists che raccontano ognuna delle librerie dove trovare le sue dipendenze. Ogni applicazione ora avrebbe libscome sottomodulo e userebbe solo le librerie necessarie.

Il test di ogni lib può essere impostato in 2 modi:

  • Core_testing, graph_testing, network_testing come applicazioni separate
  • Distribuisci le librerie testate sui server di test e trovale durante l'esecuzione dei test usando cmake

Questo non rende tutte le librerie disponibili a tutte le altre librerie?
André Caron,

Per impostazione predefinita, sì. Ma questo potrebbe essere deciso nei cmakelisti a livello di libs. Se graphnon hai bisogno di sapere network- non passare networkroba correlata a graphsubdir
Max
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.