113 votes

Détachez de nombreux sous-répertoires dans un nouveau référentiel Git distinct

Cette question est fondée sur Détacher sous-répertoire en séparer dépôt Git

Au lieu de détacher un seul sous-répertoire, je veux détacher un couple. Par exemple, mon arborescence actuelle ressemble à ceci:

/apps
  /AAA
  /BBB
  /CCC
/libs
  /XXX
  /YYY
  /ZZZ

Et je voudrais plutôt ceci:

/apps
  /AAA
/libs
  /XXX

L' --subdirectory-filter argument git filter-branch ne fonctionne pas parce qu'il se débarrasse de tout, sauf pour le répertoire donné la première fois qu'il est exécuté. J'ai pensé à l'aide de l' --index-filter argument pour tous les fichiers indésirables (quoique fastidieux), mais si j'ai essayer de l'exécuter plus d'une fois, j'obtiens le message suivant:

Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f

Des idées? TIA

126voto

David Smiley Points 1370

Au lieu d'avoir à traiter avec un sous-shell et à utiliser ext glob (comme suggéré par kynan), essayez cette approche beaucoup plus simple:

 git filter-branch --index-filter 'git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all
 

26voto

kynan Points 2334

Pourquoi voudriez-vous l'exécutez filter-branch plus d'une fois? Vous pouvez tout faire en un seul balayage, donc pas besoin de forcer (notez que vous avez besoin d' extglob activé dans votre shell pour que cela fonctionne):

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all

Cela devrait se débarrasser de tous les changements dans les indésirables sous-répertoires et de garder tous vos branches et s'engage (à moins qu'ils n'affectent les fichiers dans le taillés sous-répertoires, en vertu de l' --prune-empty) - pas de problème avec double commet etc.

Après cette opération, les indésirables, les répertoires seront répertoriés comme non chaînée en git status.

L' $(ls ...) est nécessaire.s.t. l' extglob est évalué par votre shell à la place du filtre d'index, qui utilise l' sh builtin eval (où extglob n'est pas disponible). Voir Comment activer les options d'environnement dans git? pour plus de détails sur ce point.

19voto

prisonerjohn Points 390

Pour répondre à ma propre question ici... après beaucoup d'essais et d'erreurs.

J'ai réussi à le faire en utilisant une combinaison de git subtree et git-stitch-repo. Ces instructions sont basées sur:

Tout d'abord, j'ai sorti les répertoires que je voulais garder dans leur propre référentiel:

cd origRepo
git subtree split -P apps/AAA -b aaa
git subtree split -P libs/XXX -b xxx

cd ..
mkdir aaaRepo
cd aaaRepo
git init
git fetch ../origRepo aaa
git checkout -b master FETCH_HEAD

cd ..
mkdir xxxRepo
cd xxxRepo
git init
git fetch ../origRepo xxx
git checkout -b master FETCH_HEAD

Ensuite, j'ai créé un nouveau dépôt vide, et importés/cousu les deux dernières:

cd ..
mkdir newRepo
cd newRepo
git init
git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import

Cela crée deux branches, master-A et master-B, chacun tenant le contenu de l'une des assemblées repos. De les combiner et de nettoyage:

git checkout master-A
git pull . master-B
git checkout master
git branch -d master-A 
git branch -d master-B

Maintenant, je ne suis pas tout à fait sûr de savoir comment/quand cela arrive, mais après la première checkout et de la pull, le code de la magie se mêle dans la branche master (aucune indication sur ce qui se passe ici est très appréciée!)

Tout semble avoir fonctionné comme prévu, sauf que, si je regarde à travers l' newRepo commettre l'histoire, il y a des doublons lors de la révision affecté à la fois apps/AAA et libs/XXX. Si il y a un moyen de supprimer les doublons, alors ce serait parfait.

7voto

slobobaby Points 206

J'ai écrit un filtre git pour résoudre exactement ce problème. Il porte le nom fantastique de git_filter et se trouve à github ici:

https://github.com/slobobaby/git_filter

Il est basé sur l'excellent libgit2.

Je devais scinder un grand référentiel comportant de nombreux commits (~ 100 000) et les solutions basées sur git filter-branch prenaient plusieurs jours. git_filter prend une minute pour faire la même chose.

3voto

Jakob Borg Points 10869

Ouais. Forcer le remplacement de la sauvegarde à l'aide de l'indicateur -f lors des appels suivants à filter-branch pour ignorer cet avertissement. :) Sinon, je pense que vous avez la solution (c'est-à-dire, éradiquer un répertoire indésirable à la fois avec filter-branch ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: