Fractionnement d'un sous-répertoire dans un sous-modules dépôt git séparé
-
25-09-2019 - |
Question
En tant que sous-ensemble de la question détacher-sous-répertoire déjà fait avant et compte tenu du fait que même si beaucoup de questions ont été faites au sujet du processus de dédoubler et fusionner les dépôts git, je ne pouvais pas trouver un qui touche l'objet d'une division en sous-modules sont présents.
Ainsi, dans le scénario suivant:
.git/
.gitmodules
folder/
data/
content/
other_data/
submoduleA/
submoduleB/
Je voudrais obtenir deux référentiels avec la structure suivante:
.git/
data/
et
.git/
.gitmodules
content/
other_data/
submoduleA/
submoduleB/
Le premier cas ne pose aucun problème et peut être résolu facilement avec le procédé décrit dans détacher-sous-répertoire .
Le second pas tant. L'existence de sous-modules et le fait que .gitmodules contient le chemin complet pour folder/content/submoduleA
et folder/content/submoduleB
provoque une partie de l'histoire est incompatible depuis .gitmodules fait référence à une structure de répertoire inexistant (une fois filtre-branche est utilisé).
Je voudrais savoir s'il y a un moyen de le faire sans causer de l'histoire incohérente.
La solution
Je soupçonne (non testé) qu'un deuxième git filter-branch
aurait la possibilité de modifier le contenu de .gitmodules
pour chaque commits du nouveau repo.
Mais en fait un git submodule split
commande était en discussion début 2009 .
Utilisation proposée:
git submodule split [--url submodule_repo_url] submodule_dir \
[alternate_dir...]
Remplacer
submodule_dir
avec un sous-module nouvellement créé, en gardant toute l'histoire desubmodule_dir
.
Cette commande reformule chaque validation dans l'histoire du référentiel actuel pour inclure la révision correcte desumodule_dir
et les entrées de.gitmodules
appropriées.
Cependant, je ne le vois pas dans le dernier ce qui mijote .
Le script dans le patch proposé peut vous donner une idée du type d'arbre réécriture nécessaire pour mettre à jour le fichier .gitmodules
bien.
Autres conseils
J'ai eu exactement le même problème que Unode et a réussi à le résoudre avec la procédure suivante:
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
Comme vous le voyez, l'astuce consiste à renommer temporairement le fichier .gitmodules
et utiliser sed
pour réécrire son contenu. Vous pouvez obtenir tous les détails et cadre de cette procédure sur mon blog .
Pour des précisions sur la réponse de Kevin: en supposant qu'il n'y a pas sous-modules jamais existé en dehors cool/cavemen
- le dossier étant détaché (sinon édition plus élaborée de .gitmodules sera nécessaire pour supprimer ces sections supplémentaires), cela peut être réalisé beaucoup plus rapidement et en une seule étape à l'aide d'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
Comme un avantage supplémentaire, si cool/cavemen
n'existait pas dans chaque révision ou d'une branche que les révisions ou les branches qui ne contiennent cool/cavemen
seront examinées.
Si tel est le cas, vous pouvez exécuter ce qui suit pour supprimer les références inchangées:
$ 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