Dividere una sottodirectory con sottomoduli in un repository Git separato
-
25-09-2019 - |
Domanda
Come sottoinsieme della domanda distacco-subirectory Già fatto prima e considerando il fatto che anche se sono state fatte molte domande sul processo di scissione e fusione di repository Git, non sono riuscito a trovarne uno che tocchi l'argomento della scissione quando sono presenti sottomoduli.
Quindi nel seguente scenario:
.git/
.gitmodules
folder/
data/
content/
other_data/
submoduleA/
submoduleB/
Vorrei ottenere due repository con la seguente struttura:
.git/
data/
e
.git/
.gitmodules
content/
other_data/
submoduleA/
submoduleB/
Il primo caso non è un problema e può essere risolto facilmente con il metodo descritto in distacco-subirectory.
Il secondo non così tanto. L'esistenza di sottomoduli e il fatto che .Gitmoduli contengono il percorso completo per folder/content/submoduleA
e folder/content/submoduleB
fa sì che parte della storia sia incoerente poiché .Gitmodules si riferisce a una struttura di directory inesistente (una volta utilizzata il filamento del filtro).
Quindi vorrei sapere se c'è un modo per farlo senza causare una storia incoerente.
Soluzione
Sospetto (non testato) che un secondo git filter-branch
avrebbe l'opportunità di modificare il .gitmodules
contenuto per ogni commit del nuovo repository.
Ma in realtà a git submodule split
Il comando era in discussione all'inizio del 2009.
Uso proposto:
git submodule split [--url submodule_repo_url] submodule_dir \
[alternate_dir...]
Sostituire
submodule_dir
con un sottomodulo appena creato, mantenendo tutta la storia disubmodule_dir
.
Questo comando riscrive anche ogni commit nella cronologia del repository attuale per includere la revisione corretta disumodule_dir
e l'appropriato.gitmodules
inserimenti.
Tuttavia, non lo vedo nel Ultimo cosa c'è cucina.
Lo script nella patch proposta può darti un'idea del tipo di riscrittura dell'albero necessario per aggiornare il .gitmodules
file però.
Altri suggerimenti
Ho avuto lo stesso identico problema di Usode e sono riuscito a risolverlo con la seguente procedura:
git clone git@github.com:kdeldycke/kev-code.git
cd kev-code
git filter-branch --tree-filter "test -f ./.gitmodules && mv ./.gitmodules ./cool-cavemen/gitmodules || echo 'No .gitmodules file found'" -- --all
git filter-branch --force --prune-empty --subdirectory-filter cool-cavemen --tag-name-filter cat -- --all init..HEAD
git filter-branch --force --tree-filter "test -f ./gitmodules && mv ./gitmodules ./.gitmodules || echo 'No gitmodules file found'" -- --all
git filter-branch --force --tree-filter "test -f ./.gitmodules && sed -i 's/cool-cavemen\///g' ./.gitmodules || echo 'No .gitmodules file found'" -- --all
git remote rm origin
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
git remote add origin git@github.com:kdeldycke/cool-cavemen.git
git push -u origin master --force --tags
Come vedi, il trucco è di rinominare temporaneamente il .gitmodules
file e usa sed
per riscrivere il suo contenuto. Puoi ottenere tutti i dettagli e il contesto di questa procedura sul mio blog.
Per elaborare la risposta di Kevin: supponendo che non esistessero mai sottomoduli all'esterno cool/cavemen
- La cartella staccata (altrimenti editing più elaborato di .Gitmoduli sarà necessaria per rimuovere quelle sezioni extra), questo può essere raggiunto tanto più veloce e in un passaggio usando un index-filter
:
$ git filter-branch --subdirectory-filter cool/cavemen --index-filter $'
hash=$(git rev-parse --verify $GIT_COMMIT:.gitmodules 2>/dev/null) &&
git update-index --add --cacheinfo 100644 $(git cat-file -p $hash |
sed \'s/cool\\/cavemen\\///g\' | git hash-object -w --stdin) .gitmodules ||
true' --tag-name-filter cat --prune-empty -- --all
Come ulteriore vantaggio, se cool/cavemen
non esisteva in ogni revisione o ramo solo quelle revisioni o filiali che contenevano cool/cavemen
sarà guardato.
In questo caso potresti voler eseguire quanto segue per rimuovere i riferimenti invariati:
$ git for-each-ref --format='%(refname)' |
grep -vF "$(git for-each-ref --format='%(refname)' refs/original |
sed 's/refs\/original\///g')" | xargs -n 1 git update-ref -d