Comment puis-je déplacer un seul répertoire d'un référentiel git vers un nouveau référentiel tout en conservant l'historique?

110

J'ai hérité d'un référentiel git contenant plusieurs projets dans des répertoires séparés. Je voudrais diviser le référentiel en nouveaux référentiels individuels, un pour chaque projet, puis faire en sorte que le référentiel principal contienne les projets en tant que sous-modules. J'aimerais faire tout cela tout en conservant l'historique des révisions des projets individuels si possible.

Je pourrais cloner le référentiel pour chaque projet et supprimer tous les autres projets à chaque fois, mais y a-t-il un meilleur moyen d'éviter d'avoir l'historique cloné dans chaque nouveau référentiel de projet?

cédé
la source
2
Ajout de la balise git-submodules car elle est très utile pour convertir une partie d'un dépôt en sous-module.
idbrii

Réponses:

99

Vous pouvez utiliser git filter-branchpour réécrire l'historique d'un projet. De la documentation:

Pour réécrire le référentiel pour donner l'impression que foodir / avait été la racine de son projet et supprimer toute autre histoire:

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

Faites plusieurs copies de votre dépôt, faites-le pour chaque sous-répertoire que vous souhaitez diviser et vous devriez vous retrouver avec ce que vous recherchez.

Brian Campbell
la source
1
Et si je voulais exclure foodir et supprimer toute son histoire?
saeedgnu
1
Remarque: si vous voulez plusieurs répertoires, vous devrez spécifier --subdirectory-filterplusieurs fois. EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardir, etc. --subdirectoryne prendront pas plusieurs répertoires, mais peuvent être spécifiés plusieurs fois.
EnabrenTane
3
@Adam Si vous souhaitez conserver l'historique de foodirdans le projet d'origine, sans réécrire son historique, cela git rm -r foodirdevrait suffire (cela supprimera également la copie dans votre arbre de travail; si vous ne le souhaitez pas, utilisez --cached). Si vous vouliez le supprimer entièrement de l'historique (en répondant également à la question de @ ilius), vous voulez quelque chose commegit filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell
2
@ilius Désolé, j'ai manqué votre question plus tôt, voir ma réponse ci-dessus pour savoir comment supprimer un répertoire et son historique.
Brian Campbell
2
@ilius Oui, ça marche aussi. Pour un grand projet, la --index-filtersolution est plus rapide que le --tree-filter, car elle n'a pas à extraire réellement les fichiers, elle peut simplement manipuler l'index directement. Le --tree-filterpeut être un peu plus facile à utiliser cependant, car vous pouvez utiliser des opérations de système de fils ordinaires plutôt que d'avoir à travailler avec des opérations de manipulation d'index.
Brian Campbell
4

Pour exporter un dossier en tant que nouveau référentiel, vous avez besoin:

  1. Pour cloner le référentiel dans lequel se trouve le dossier que vous souhaitez exporter.
  2. Pour créer un référentiel vide sur votre fournisseur d'hébergement en tant que GitHub, pour stocker le dossier exporté.
  3. Ouvrez le dossier du référentiel cloné et exécutez cette commande:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    
utilisateur
la source
1
git subtreen'est pas disponible en tant que package Cygwin. Si vous en avez besoin: stackoverflow.com/a/27116828/2484903
Jack Miller
2

L'intérêt de git est que l'historique est incorporé dans chaque commit en hachant le commit parent. Vous pouvez "rejouer" les commits (c'est essentiellement ainsi que fonctionne svn-importer) dans un nouveau référentiel et ne conserver que chaque sous-projet. Ceci, cependant, détruirait la signification des hachages de commit. Si cela ne vous pose aucun problème, qu'il en soit ainsi.

Dans le passé, je viens de le cloner et de passer à autre chose. Cela rend les choses plus grandes mais l'espace disque est bon marché; mon temps coûte cher.

Je ne connais pas non plus d'outils pour épisser un répertoire. Je suppose que vous pouvez git-log sur le répertoire pour trouver tous les commits dessus, puis rejouer les commits avec quelque chose comme git-fast-export?

Colin Burnett
la source
J'ai voté pour parce que cela ne méritait pas d'être négatif - je ne suivrais certainement pas cette approche mais je peux voir qu'il essayait
Alvin