Non copiare i file, ma unire i repository. Git non fa una grande differenza tra "repository differenti" e "filiali diverse". Più precisamente, un repository è una raccolta di tag e rami. Presumo che tu voglia unire il ramo principale di tutti i repository.
Approccio generale (ma vedi la discussione di git-sottoalbero di seguito):
-
Pensa al layout del tuo monorepo. Suppongo che all'inizio, avrai ogni repository corrente come sottocartella del monorepo per evitare conflitti.
-
Per ogni repository attuale, sposta il contenuto del repository in una sottocartella e conferma la modifica. Puoi usare il comando git mv
per farlo facilmente.
es. se il tuo componente è chiamato libfoo
e attualmente disponi di questo layout del repository:
Makefile
README.txt
src/
...
include/
...
Quindi potremmo spostarlo in una cartella libfoo/
:
libfoo/
Makefile
README.txt
src/
...
include/
...
-
Crea un nuovo repository per il tuo monorepo e aggiungi tutti i repository esistenti come "remoto". Nonostante il suo nome, un repository remoto può essere un percorso verso qualche directory sullo stesso file system. Quindi git fetch --all
remoti per caricare la loro cronologia nel database git di monorepo. Successivamente, puoi elencare tutti i rami con git branch --all
. Sembrerà:
* master
remotes/libfoo/master
remotes/libbar/master
...
-
Per ciascun telecomando, unisci il suo ramo principale. Non ci dovrebbero essere conflitti perché tutto è in una directory separata.
-
Ora hai finito, e hai un monorepo senza perdita di cronologia. Puoi rimuovere i telecomandi.
Ma attenzione: puoi unire solo un ramo di ciascun repository. Se uno dei repository originali ha più rami, non possono più essere uniti senza conflitti eccessivi. Considera di ridistribuirli dopo aver spostato i contenuti del repository in una cartella, ma prima di unire tutto nel monorepo.
In pratica, puoi utilizzare git subtree
per automatizzare la maggior parte di questi passaggi. Il comando sottostruttura consente di unire un ramo specifico in una directory specifica.
- inizializza il monorepo e crea almeno un commit
-
per ogni repository esistente, aggiungilo come sottostruttura, ad esempio:
git subtree add -P libfoo/ ../path/to/libfoorepo master
Il -P
/ --prefix
è la directory in cui deve essere aggiunto il contenuto del repository. Al posto del percorso di un repository, è possibile utilizzare qualsiasi URL di repository. Per impostazione predefinita, questo aggiungerà la cronologia completa, in alternativa puoi --squash
della cronologia in un singolo commit.
Il sottoalbero di Git è uno strumento estremamente potente per manipolare i monoropos. Puoi anche estrarre una directory in un repository separato ( git subtree push
) o unire gli aggiornamenti dal repository originale ( git subtree pull
). Ad esempio, potresti usarlo per tradurre diversi rami.
- Per tradurre un ramo
feature
:
- Crea un nuovo ramo nel monorepo:
git checkout -b feature
- Tira le modifiche dal% co_de di libfoo alla directory corretta del monorepo:
feature
.
- Opzionale: rebase il ramo sul master per semplificare il grafico della cronologia.
Ma considera se un monorepo è veramente appropriato per il tuo caso d'uso. Potrebbe essere comunque preferibile avere diversi repository disponibili indipendentemente. Il concorrente principale è git submodules, dove un repository è montato come sottodirectory di un altro. Tuttavia, l'esperienza non è perfetta. La cronologia del ramo non è condivisa con il sottomodulo. Se si modifica il codice in un sottomodulo, è necessario eseguire il commit separatamente. I sottomoduli Git sono molto utili per le dipendenze esterne "vendor" che vengono aggiunte a una versione specifica, non per lo sviluppo combinato.
Qualunque approccio tu usi, i file gitignore continueranno a funzionare perché tutti i pattern sono abbinati rispetto al file gitignore. Un repository può contenere più file gitignore.