J'ai une application Web qui explore d'autres applications Web d'une manière particulière. Il contient des démos Web dans un dossier demos
et l'une des démos devrait maintenant avoir son propre référentiel. Je souhaite créer un référentiel distinct pour cette application de démonstration et en faire un sous-emballage sous-module du référentiel principal sans perdre son historique de validation.
Est-il possible de conserver l'historique de validation des fichiers dans le dossier d'un référentiel, de créer un référentiel à partir de celui-ci et de l'utiliser comme sous-module ?
Voir la note à la fin de cette réponse (dernier paragraphe) pour une alternative rapide aux sous-modules git utilisant npm;)
Dans la réponse suivante, vous saurez comment extraire un dossier d'un référentiel et en faire un référentiel git, puis l'inclure en tant que sous-module au lieu d'un dossier.
Inspiré de l'article de Gerg Bayer Déplacement de fichiers d'un référentiel Git vers un autre, préservation de l'historique
Au début, nous avons quelque chose comme ceci:
<git repository A>
someFolders
someFiles
someLib <-- we want this to be a new repo and a git submodule!
some files
Dans les étapes ci-dessous, je vais appeler ceci someLib
comme <directory 1>
.
À la fin, nous aurons quelque chose comme ceci:
<git repository A>
someFolders
someFiles
@submodule --> <git repository B>
<git repository B>
someFolders
someFiles
Obtenez une nouvelle copie du référentiel à scinder.
git clone <git repository A url>
cd <git repository A directory>
Le dossier actuel sera le nouveau référentiel afin de supprimer la télécommande actuelle.
git remote rm Origin
Extraire l’historique du dossier souhaité et le valider
git filter-branch --subdirectory-filter <directory 1> -- --all
Vous devriez maintenant avoir un dépôt git avec les fichiers de directory 1
dans la racine de votre référentiel avec tous les historiques de validation associés.
Créez votre référentiel en ligne et poussez votre nouveau référentiel!
git remote add Origin <git repository B url>
git Push
Vous devrez peut-être définir la branche upstream
pour votre premier Push
git Push --set-upstream Origin master
<git repository A>
_ (facultatif, voir les commentaires)Nous voulons supprimer les traces (fichiers et historique de commit) de <git repository B>
de <git repository A>
donc l’historique de ce dossier n’est présent qu’une fois.
Ceci est basé sur Suppression des données sensibles de github.
Allez dans un nouveau dossier et
git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --Prune-empty --tag-name-filter cat -- --all
Remplacer <directory 1>
par le dossier que vous souhaitez supprimer. -r
le fera récursivement à l'intérieur du répertoire spécifié :). Maintenant, appuyez sur Origin/master
avec --force
git Push Origin master --force
Créez un sous-module à partir de <git repository B>
en <git repository A>
git submodule add <git repository B url>
git submodule update
git commit
Vérifiez si tout a fonctionné comme prévu et Push
git Push Origin master
Après tout cela, je me suis rendu compte dans mon cas qu'il était plus approprié d'utiliser npm pour gérer mes propres dépendances. Nous pouvons spécifier les URLs et les versions de Git, voir les RL de package.json git en tant que dépendances .
Si vous procédez ainsi, le référentiel que vous souhaitez utiliser en tant qu'exigence doit être un module npm , de sorte qu'il doit contenir un package.json
fichier ou vous obtiendrez cette erreur: Error: ENOENT, open 'tmp.tgz-unpack/package.json'
.
Vous trouverez peut-être qu'il est plus facile d'utiliser npm et gérer les dépendances à l'aide d'URL git :
npm init
à l'intérieur des deux référentielsnpm install --save git://github.com/user/project.git#commit-ish
où vous voulez installer vos dépendancesLa solution de @GabLeRoux écrase les branches et les commits correspondants.
Un moyen simple de cloner et de conserver toutes ces branches et commits supplémentaires:
1 - Assurez-vous d'avoir cet 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 - Cloner la télécommande, extraire toutes les branches, changer la télécommande, filtrer votre répertoire, Push
git clone [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm Origin
git remote add Origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git Push --all
git Push --tags
La solution de GabLeRoux fonctionne bien sauf si vous utilisez git lfs
et contient des fichiers volumineux dans le répertoire que vous souhaitez détacher. Dans ce cas, après l'étape 3, tous les fichiers volumineux resteront des fichiers de pointeur au lieu de fichiers réels. Je suppose que c'est probablement dû au .gitattributes
fichier en cours de suppression dans le processus de branche de filtrage.
En réalisant cela, je trouve la solution suivante qui fonctionne pour moi:
cp .gitattributes .git/info/attributes
Copie .gitattributes
que git lfs utilise pour suivre les gros fichiers sur .git/
répertoire pour éviter d'être supprimé.
Lorsque le filtre-branche est terminé, n'oubliez pas de remettre le .gitattributes
_ si vous voulez toujours utiliser git lfs pour le nouveau référentiel:
mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'