Crea un repository di submodule da una cartella e mantieni la sua cronologia di commit git

Ho un’applicazione web che esplora altre applicazioni web in un modo particolare. Contiene alcune demo web in una cartella demos e una demo dovrebbe ora avere il proprio repository. Vorrei creare un repository separato per questa applicazione demo e renderlo un sottopackage sottomodulo dal repository principale senza perdere la cronologia dei commit.

È ansible mantenere la cronologia dei commit dai file nella cartella di un repository e creare un repository da esso e utilizzarlo come sottomodulo ?

    Soluzione dettagliata

    Vedere la nota alla fine di questa risposta (ultimo paragrafo) per una rapida alternativa ai sottomoduli git usando npm;)

    Nella risposta seguente, saprai come estrarre una cartella da un repository e creare un repository git da esso e quindi includerlo come sottomodulo anziché come cartella.

    Ispirato dall’articolo di Gerg Bayer, spostare i file da un repository Git ad un altro, preservando la cronologia

    All’inizio, abbiamo qualcosa di simile a questo:

      someFolders someFiles someLib < -- we want this to be a new repo and a git submodule! some files 

    Nei passaggi seguenti, mi riferirò a questo someLib come .

    Alla fine, avremo qualcosa di simile a questo:

      someFolders someFiles @submodule -->   someFolders someFiles 

    Crea un nuovo repository git da una cartella in un altro repository

    Passo 1

    Ottieni una nuova copia del repository da dividere.

     git clone  cd  

    Passo 2

    La cartella corrente sarà il nuovo repository, quindi rimuovi il telecomando corrente.

     git remote rm origin 

    Passaggio 3

    Estrai la cronologia della cartella desiderata e eseguila

     git filter-branch --subdirectory-filter  -- --all 

    Ora dovresti avere un repository git con i file della directory 1 nella root del repository con tutta la cronologia dei commit relativa.

    Passaggio 4

    Crea il tuo repository online e invia il tuo nuovo repository!

     git remote add origin  git push 

    Potrebbe essere necessario impostare il ramo upstream per la prima spinta

     git push --set-upstream origin master 

    Pulisci (opzionale, vedi commenti)

    Vogliamo cancellare tracce (file e cronologia commit) di da così la cronologia per questa cartella è presente solo una volta.

    Questo si basa sulla rimozione di dati sensibili da github.

    Vai a una nuova cartella e

     git clone  cd  git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch  -r' --prune-empty --tag-name-filter cat -- --all 

    Sostituisci dalla cartella che vuoi rimuovere. -r lo farà in modo ricorsivo all'interno della directory specificata :). Adesso premi su origin/master con --force

     git push origin master --force 

    Boss Stage (vedi nota sotto)

    Crea un sottomodulo da in

     git submodule add  git submodule update git commit 

    Verifica se tutto ha funzionato come previsto e push

     git push origin master 

    Nota

    Dopo aver fatto tutto questo, mi sono reso conto nel mio caso che era più appropriato usare npm per gestire le mie dipendenze. Possiamo specificare git url e versioni, vedere gli url di git package.json come dipendenze .

    Se lo fai in questo modo, il repository che vuoi utilizzare come requisito deve essere un modulo npm, quindi deve contenere un file package.json o riceverai questo errore: Error: ENOENT, open 'tmp.tgz-unpack/package.json' .

    tldr (soluzione alternativa)

    Potresti trovare più facile usare npm e gestire le dipendenze con url git :

    • Sposta la cartella in un nuovo repository
    • eseguire npm init all'interno di entrambi i repository
    • eseguire npm install --save git://github.com/user/project.git#commit-ish dove vuoi installare le tue dipendenze

    La soluzione di @GabLeRoux schiaccia i rami e il relativo commit.

    Un modo semplice per clonare e mantenere tutti quei rami extra e commettere:

    1 – Assicurati di avere questo alias git

     git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t' 

    2 – Clona il telecomando, tira tutti i rami, cambia il telecomando, filtra la tua directory, premi

     git clone git@github.com:user/existing-repo.git new-repo cd new-repo git clone-branches git remote rm origin git remote add origin git@github.com:user/new-repo.git git remote -v git filter-branch --subdirectory-filter my_directory/ -- --all git push --all git push --tags 

    La soluzione di GabLeRoux funziona bene, tranne se si utilizza git lfs e ha file di grandi dimensioni sotto la directory che si desidera staccare. In tal caso, dopo il passaggio 3 tutti i file di grandi dimensioni rimarranno file puntatore anziché file reali. Immagino sia dovuto probabilmente al file .gitattributes che viene rimosso nel processo del ramo del filtro.

    Realizzando questo, trovo che la seguente soluzione funzioni per me:

     cp .gitattributes .git/info/attributes 

    Copiare .gitattributes che git lfs usa per tracciare file di grandi dimensioni in .git/ directory per evitare di essere cancellato.

    Quando il filtro-ramo è .gitattributes non dimenticare di rimettere i .gitattributes se vuoi ancora utilizzare git lfs per il nuovo repository:

     mv .git/info/attributes .gitattributes git add .gitattributes git commit -m 'added back .gitattributes'