Détacher (déplacer) sous-répertoire dans le référentiel Git séparé
-
21-08-2019 - |
Question
Comment puis-je faire cela tout en gardant l'histoire des fichiers dans le sous-répertoire?
Je suppose que je pourrais faire un clone et enlever les parties indésirables de chaque clone, mais je suppose que cela me donnerait l'arbre complet lors de la vérification d'une version plus ancienne, etc. Cela pourrait être acceptable, mais je préférerais pouvoir prétendre que les deux dépôts ne sont pas une histoire commune.
Juste pour préciser, j'ai la structure suivante:
XYZ/
.git/
XY1/
ABC/
XY2/
Mais je voudrais ceci:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
La solution
Mise à jour : Ce processus est si commun, que l'équipe git fait beaucoup plus simple avec un nouvel outil, git subtree
. Voir ici: Détacher (déplacer) sous-répertoire dans le référentiel Git séparé
Vous voulez cloner votre dépôt et ensuite utiliser pour marquer tout git filter-branch
mais le sous-répertoire que vous voulez dans votre nouveau repo à recueillir les déchets.
-
Pour cloner votre référentiel local:
git clone /XYZ /ABC
(Note:. Le dépôt sera cloné en utilisant les liens physiques, mais qui ne sont pas un problème car les fichiers difficiles liés ne seront pas modifiés en eux-mêmes - de nouveaux seront créés)
-
Maintenant, Conservons les branches intéressantes que nous voulons réécrire ainsi, puis retirez l'origine pour éviter de pousser là-bas et faire en sorte que les anciens commits ne seront pas référencés par l'origine:
cd /ABC for i in branch1 br2 br3; do git branch -t $i origin/$i; done git remote rm origin
ou pour toutes les branches à distance:
cd /ABC for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done git remote rm origin
-
Maintenant, vous pouvez également supprimer les balises qui ont aucun rapport avec le sous-projet; vous pouvez aussi le faire plus tard, mais vous devrez peut-être élaguer à nouveau votre pension. Je ne le faisais pas et a obtenu un pour tous les tags
WARNING: Ref 'refs/tags/v0.1' is unchanged
(car ils étaient tous sans rapport avec le sous-projet); En outre, après avoir retiré ces étiquettes plus d'espace seront remises en état. Apparemment, devrait être en mesuregit tag -l | xargs git tag -d
de réécrire d'autres balises, mais je ne pouvais pas vérifier. Si vous souhaitez supprimer tous les tags, utilisez--tag-name-filter cat --prune-empty
. -
Ensuite, utilisez le filtre-branche et remis à zéro pour exclure les autres fichiers, afin qu'ils puissent être élagué. Ajoutons également supprimer commits
-- --all
vides et de réécrire les balises (notez que cela devra dépouiller leur signature):git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
ou bien, de réécrire uniquement la branche de la tête et ne pas tenir compte des balises et d'autres branches:
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
-
Ensuite, supprimez les reflogs de sauvegarde si l'espace peut être vraiment récupéré (bien que maintenant l'opération est destructive)
git reset --hard git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d git reflog expire --expire=now --all git gc --aggressive --prune=now
et maintenant vous avez un dépôt git local du sous-répertoire ABC avec toute son histoire préservée.
Note: Pour la plupart des utilisations, en effet devrait avoir all
le paramètre ajouté <=>. Oui, c'est vraiment - - Espace - - <=>. Cela doit être les derniers paramètres de la commande. Comme Matli a découvert, ce qui maintient les branches du projet et les balises incluses dans le nouveau repo.
Edit:. Diverses suggestions de commentaires ci-dessous ont été intégrés pour vous assurer, par exemple, que le dépôt est en fait diminué (ce qui n'a pas toujours été le cas avant)
Autres conseils
The Easy Way ™
Il se trouve que c'est une pratique courante et utile que les suzerains de git fait vraiment facile, mais vous devez avoir une version plus récente de git (> = 1.7.11 mai 2012). Voir annexe pour savoir comment installer la dernière git. En outre, il y a un par exemple dans le monde réel soluce ci-dessous.
-
Préparer l'ancien repo
pushd <big-repo> git subtree split -P <name-of-folder> -b <name-of-new-branch> popd
Remarque:
<name-of-folder>
ne doivent pas contenir des caractères avant ou arrière. Par exemple, le dossier nommé DOIT être passésubproject
comme./subproject/
, NOTpath1\path2\subproject
Remarque pour les utilisateurs de Windows: lorsque la profondeur du dossier est> 1, doit avoir *
path1/path2/subproject
séparateur de dossiers de style nix (/). Par exemple, le dossier nommé DOIT être passé.git
comme<meta-named-things>
-
Créer le nouveau repo
mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
-
Lier le nouveau repo à Github ou chaque fois que
git remote add origin <git@github.com:my-user/new-repo.git> git push origin -u master
-
Nettoyage, si on le souhaite
popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>
Remarque : Cela laisse toutes les références historiques dans le repository.See le ci-dessous si vous êtes réellement concernés Annexe d'avoir commis un mot de passe ou vous avez besoin pour diminuer la la taille du fichier de votre dossier
btoa
.
...
Walkthrough
Ce sont les mêmes étapes ci-dessus , mais après mes étapes exactes pour mon dépôt au lieu d'utiliser btoa-only
.
Voici un projet que j'ai pour la mise en œuvre des modules de navigateur JavaScript dans le noeud:
tree ~/Code/node-browser-compat
node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator
Je veux diviser un seul dossier, origin
, dans un dépôt git séparé
pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd
J'ai maintenant une nouvelle branche, README.md
, qui a seulement pour commits et je veux .gitignore
créer un nouveau référentiel.
mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only
Ensuite, je crée un nouveau repo sur Github ou bitbucket, ou tout et ajoutez-le LICENSE
(BTW, « origine » est juste une convention, ne fait pas partie de la commande - vous pouvez l'appeler « serveur distant » ou ce que vous voulez)
git remote add origin git@github.com:node-browser-compat/btoa.git
git push origin -u master
Happy day!
Remarque: Si vous avez créé une prise en pension avec un git pull
, et git push
<=>, vous devrez tirer d'abord:
git pull origin -u master
git push origin -u master
Enfin, je veux supprimer le dossier du plus grand repo
git rm -rf btoa
...
Annexe
Dernières git sur OS X
Pour obtenir la dernière version de git:
brew install git
Pour brasser pour OS X:
Dernières git sur Ubuntu
sudo apt-get update
sudo apt-get install git
git --version
Si cela ne fonctionne pas (vous avez une version très ancienne de ubuntu), essayez
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git
Si cela ne fonctionne toujours pas, essayez
sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree
Merci à rui.araujo des commentaires.
effacer votre historique
Par défaut la suppression des fichiers de git ne les supprime pas réellement de git, il engage juste qu'ils ne sont plus là. Si vous voulez réellement supprimer les références historiques (à savoir que vous avez un commis un mot de passe), vous devez faire ceci:
git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD
Après cela, vous pouvez vérifier que votre fichier ou le dossier ne montre plus dans l'histoire git du tout
git log -- <name-of-folder> # should show nothing
Cependant, vous ne pouvez pas "pousser" supprime à github et similaires. Si vous essayez de vous obtiendrez une erreur et vous devrez avant de pouvoir <=> <=> -. Et vous êtes de retour à avoir tout dans votre histoire
Donc, si vous voulez supprimer l'historique de la « origine » - ce qui signifie pour le supprimer de GitHub, bitbucket, etc - vous devrez supprimer le repo et re-pousser une copie élagué du repo. Mais attendez - il y a plus ! -. Si vous êtes vraiment préoccupé de se débarrasser d'un mot de passe ou quelque chose comme ça, vous aurez besoin d'élaguer la sauvegarde (voir ci-dessous)
faire plus petits <=> h2>
La commande Supprimer l'histoire ci-dessus laisse encore derrière un tas de fichiers de sauvegarde - parce que git est trop gentil pour vous aider à ne pas ruiner votre repo par accident. Il finira par supprimer des fichiers orphelins au cours des jours et des mois, mais il y laisse pendant un certain temps dans le cas où vous vous rendez compte que vous avez accidentellement supprimé quelque chose que vous ne vouliez pas.
Donc, si vous voulez vraiment vider la corbeille réduire la taille du clone d'unrepo immédiatement vous devez faire tout ce genre de choses vraiment bizarre:
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune=now
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
Cela dit, je vous recommande de ne pas effectuer ces étapes sauf si vous savez que vous devez - juste au cas où vous ne taillez le mauvais sous-répertoire, tu vois? Les fichiers de sauvegarde ne doivent pas se clonés lorsque vous appuyez sur le repo, ils seront juste dans votre copie locale.
Crédit
réponse de Paul crée un nouveau référentiel contenant / ABC, mais ne supprime pas / ABC de l'intérieur / XYZ. La commande suivante supprime / ABC de l'intérieur / XYZ:
git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD
Bien sûr, le tester dans un «clone --no-référentiel de liens physiques d'abord, et de le suivre avec les commandes de réinitialisation, gc et pruneau liste Paul.
J'ai trouvé que pour supprimer correctement l'histoire ancienne du nouveau référentiel, vous devez faire un peu plus de travail après l'étape filter-branch
.
-
Faites le clone et le filtre:
git clone --no-hardlinks foo bar; cd bar git filter-branch --subdirectory-filter subdir/you/want
-
Supprimer toute référence à l'histoire ancienne. « Origine » a été suivi de votre clone, et « original » est l'endroit où le filtre branche enregistre les vieux trucs:
git remote rm origin git update-ref -d refs/original/refs/heads/master git reflog expire --expire=now --all
-
Même maintenant, votre histoire pourrait être coincé dans un packfile que fsck ne touche pas. Déchirer en lambeaux, créant ainsi une nouvelle packfile et de supprimer les objets non utilisés:
git repack -ad
Il est une explication de cette dans le pour le filtre-branche .
Edit: script Bash ajouté
.Les réponses ont travaillé ici que partiellement pour moi; Beaucoup de gros fichiers sont restés dans le cache. Ce qui a finalement travaillé (après les heures à #git sur freenode):
git clone --no-hardlinks file:///SOURCE /tmp/blubb
cd blubb
git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT --prune-empty --tag-name-filter cat -- --all
git clone file:///tmp/blubb/ /tmp/blooh
cd /tmp/blooh
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now
Avec les solutions précédentes, la taille du référentiel était d'environ 100 MB. Celui-ci a apporté à 1,7 MB. Peut-être que cela aide quelqu'un:)
Le script bash suivant automatise la tâche:
!/bin/bash
if (( $# < 3 ))
then
echo "Usage: $0 </path/to/repo/> <directory/to/extract/> <newName>"
echo
echo "Example: $0 /Projects/42.git first/answer/ firstAnswer"
exit 1
fi
clone=/tmp/${3}Clone
newN=/tmp/${3}
git clone --no-hardlinks file://$1 ${clone}
cd ${clone}
git filter-branch --subdirectory-filter $2 --prune-empty --tag-name-filter cat -- --all
git clone file://${clone} ${newN}
cd ${newN}
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now
Ce ne l'est plus complexe, vous pouvez simplement utiliser le commande sur un clone de vous repo à abattre les sous-répertoires que vous ne voulez pas et pousser à la nouvelle télécommande.
git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .
Mise à jour : Le module git-sous-arbre était si utile que l'équipe git tiré dans noyau et fait git subtree
. Voir ici: Détacher (déplacer) sous-répertoire dans le référentiel Git séparé
git-sous-arbre peut être utile pour cette
http://github.com/apenwarr/git -subtree / blob / maître / git-subtree.txt (obsolète)
http: // psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/
Voici une petite modification CoolAJ86 's " The Easy Way ™ » répondre afin de diviser plusieurs sous-dossiers (disons et sub1
sub2
) dans un nouveau dépôt git.
The Easy Way ™ (Multiple sous-dossiers)
-
Préparer l'ancien repo
pushd <big-repo> git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD git subtree split -P <name-of-folder> -b <name-of-new-branch> popd
Remarque:
<name-of-folder>
ne doivent pas contenir des caractères avant ou arrière. Par exemple, le dossier nommé DOIT être passésubproject
comme./subproject/
, NOTpath1\path2\subproject
Remarque pour les utilisateurs de Windows: lorsque la profondeur du dossier est> 1, doit avoir *
path1/path2/subproject
séparateur de dossiers de style nix (/). Par exemple, le dossier nommé DOIT être passémv
commemove
. De plus, ne pas utiliser la commande maisgit filter-branch...
.git
.Note finale: la différence unique et grande avec la réponse de base est la deuxième ligne du script "<=>"
-
Créer le nouveau repo
mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
-
Lier le nouveau repo à Github ou chaque fois que
git remote add origin <git@github.com:my-user/new-repo.git> git push origin -u master
-
Nettoyage, si on le souhaite
popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>
Remarque : Cela laisse toutes les références historiques dans le repository.See le si vous êtes réellement concernés Annexe dans la réponse originale d'avoir commis un mot de passe ou vous avez besoin à la diminution de la taille du fichier de votre dossier <=>.
La question initiale veut XYZ / ABC / (* fichiers) pour devenir ABC / ABC / (fichiers *). Après la mise en œuvre de la réponse acceptée pour mon propre code, j'ai remarqué que cela change réellement XYZ / ABC / (* fichiers) dans (fichiers *) ABC /. La page de manuel filter-branch dit même,
Le résultat contiendra ce répertoire (et seulement) comme racine du projet « .
En d'autres termes, il favorise le dossier haut niveau « haut » un niveau. C'est une distinction importante parce que, par exemple, dans mon histoire, je l'avais renommé un dossier de niveau supérieur. En faisant la promotion des dossiers « up » d'un niveau, git perd la continuité au commit où je l'ai fait le changement de nom.
Ma réponse à la question est alors de faire 2 copies du dépôt et supprimer manuellement le dossier (s) que vous souhaitez conserver dans chaque. La page de manuel me soutient avec ceci:
[...] éviter d'utiliser [cette commande] si un engagement simple, suffirait à résoudre votre problème
Pour ajouter réponse de Paul , je trouve que pour récupérer finalement l'espace, je dois pousser la tête d'un référentiel propre et que les garnitures sur la taille de la .git / objects / pack.
i.e..
$ mkdir ...ABC.git $ cd ...ABC.git $ git init --bare
Après la pruneau gc, faire aussi:
$ git push ...ABC.git HEAD
Ensuite, vous pouvez faire
$ git clone ...ABC.git
et la taille de ABC / .git est réduit
En fait, de temps en temps des étapes consommation (par exemple git gc) ne sont pas nécessaires avec la poussée pour nettoyer dépôt, i.e.:.
$ git clone --no-hardlinks /XYZ /ABC $ git filter-branch --subdirectory-filter ABC HEAD $ git reset --hard $ git push ...ABC.git HEAD
Une bonne façon est maintenant le suivant:
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
GitHub maintenant ont même petit article sur ces cas.
Mais assurez-vous de cloner votre repo d'origine dans le répertoire séparé premier (car il supprimerait tous les fichiers et d'autres répertoires et vous avez besoin probable de travailler avec eux).
Ainsi, votre algorithme doit être:
- cloner votre repo à distance dans un autre répertoire
- en utilisant uniquement les fichiers laissés
git filter-branch
sous un sous-répertoire, appuyez sur la nouvelle télécommande - Que engager à supprimer ce sous-répertoire de votre repo à distance d'origine
Il semble que la plupart (tous?) Des réponses comptent ici sur une certaine forme de son acabit et git filter-branch --subdirectory-filter
. Cela peut fonctionner « la plupart du temps » mais pour certains cas, par exemple le cas quand vous avez renommé le dossier, ex:
ABC/
/move_this_dir # did some work here, then renamed it to
ABC/
/move_this_dir_renamed
Si vous faites un style de filtre git normale pour extraire « move_me_renamed » vous perdrez l'historique des changements de fichier qui a eu lieu du dos quand il a d'abord été move_this_dir ( ref ).
Il apparaît donc que la seule façon de vraiment garder tous l'histoire du changement (si le vôtre est un cas comme celui-ci), est, en substance, de copier le référentiel (créer un nouveau repo, définissez que être à l'origine), l'arme nucléaire alors tout le reste et renommer le sous-répertoire parent comme ceci:
- Clone localement le projet multi-module
- Branches - vérifier ce qui est là:
git branch -a
- Faites une caisse pour chaque branche à inclure dans la division pour obtenir une copie locale sur votre poste de travail:
git checkout --track origin/branchABC
- Faites une copie dans un nouveau répertoire:
cp -r oldmultimod simple
- Allez dans la nouvelle copie du projet:
cd simple
- Débarrassez-vous des autres modules qui ne sont pas nécessaires dans ce projet:
-
git rm otherModule1 other2 other3
- Maintenant que le subdir du module cible reste
- Débarrassez-vous du module subdir de sorte que la racine du module devient la nouvelle racine du projet
-
git mv moduleSubdir1/* .
- Supprimer la relique subdir:
rmdir moduleSubdir1
- Vérifier les modifications à tout moment:
git status
- Créer le nouveau git et copier son URL pour pointer ce projet en elle:
-
git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
- Vérifiez ce qui est bon:
git remote -v
- Appuyez sur les modifications à la prise en pension à distance:
git push
- Aller à la prise en pension à distance et vérifiez qu'il est là tous
- Répéter pour toute autre branche nécessaire:
git checkout branch2
le github doc " fractionnement d'un sous-dossier sur dans un nouveau dépôt " étapes 6-11 pour pousser le module à un nouveau repo.
Cela ne vous sauvera pas d'espace dans votre dossier .git, mais il conservera tout votre historique des modifications pour les fichiers même à travers renomme. Et cela peut ne pas être la peine s'il n'y a pas « beaucoup » de l'histoire perdue, etc. Mais au moins vous êtes assuré de ne pas perdre plus engage!
J'ai eu exactement ce problème, mais toutes les solutions standard basées sur git filtre branche est extrêmement lent. Si vous avez un petit dépôt, alors ce ne peut pas être un problème, il était pour moi. J'ai écrit un autre programme de filtrage git basé sur libgit2 qui, comme une première étape crée des branches pour chaque filtrage du dépôt primaire et pousse alors ceux-ci pour nettoyer les dépôts comme l'étape suivante. Sur mon dépôt (500Mo) 100000 commits les méthodes git filtre standard branche ont jours. Mon programme prend quelques minutes pour faire le même filtrage.
Il a le nom fabuleux de git_filter et vit ici:
https://github.com/slobobaby/git_filter
sur GitHub.
J'espère qu'il est utile à quelqu'un.
Pour ce que ça vaut la peine, voici comment l'utilisation GitHub sur une machine Windows. Disons que vous avez une prise en pension clonés résidant à C:\dir1
. La structure du répertoire ressemble à ceci: C:\dir1\dir2\dir3
. Le répertoire est celui dir3
je veux être un nouveau repo séparé.
Github:
- Créez votre nouveau référentiel:
MyTeam/mynewrepo
Bash Invite:
-
$ cd c:/Dir1
-
$ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
Renvoyée:Ref 'refs/heads/master' was rewritten
(fyi. Dir2 / dos3 est sensible à la casse) -
$ git remote add some_name git@github.com:MyTeam/mynewrepo.git
git remote add origin etc
. ne fonctionnait pas, retourné "remote origin already exists
" -
$ git push --progress some_name master
Comme je l'ai mentionné plus haut , je devais utiliser l'inverse solution (suppression ne touche pas tous les commits mon dir/subdir/targetdir
) qui semblait fonctionner assez bien enlever environ 95% des commits (comme on le souhaite). Cependant, il y a deux petites questions en suspens.
FIRST , a fait un coup filter-branch
up travail d'enlever commits qui introduisent ou modifient le code, mais apparemment, fusion commits sont sous sa station dans le Gitiverse.
Ceci est un problème esthétique que je peux probablement vivre avec (il dit ... reculant lentement en détournant les yeux) .
SECOND les quelques commits qui restent sont à peu près ALL en double! Il me semble avoir acquis une seconde, le calendrier redondant qui couvre à peu près toute l'histoire du projet. La chose intéressante (que vous pouvez voir sur la photo ci-dessous), est que mes trois branches locales ne sont pas tous sur la même ligne de temps (ce qui est, sans aucun doute pourquoi il existe et est non seulement les déchets collectés).
La seule chose que je peux imaginer que l'un des commits supprimés était, peut-être, la fusion unique commit que <=> en fait ne supprimer , et qui a créé la chronologie parallèle chaque maintenant unmerged volet a sa propre copie des commits. ( haussement Où est mon TARDIS?) Je suis sûr que je peux résoudre ce problème, mais je vraiment aime comprendre comment il est arrivé.
Dans le cas de fou mergefest-O-RAMA, je vais probablement quittais qu'une seule personne car elle a donc se fermement ancrée dans mon histoire commettre menaçant à moi chaque fois que je viens quasi, il ne semble pas être à l'origine en fait des problèmes non esthétiques et parce qu'il est tout à fait assez dans Tower.app.
Utilisez cette commande de filtre pour supprimer un sous-répertoire, tout en préservant vos balises et des branches:
git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
La façon plus facile
-
git splits
. Je l'ai créé comme une extension git, basé sur la solution jkeating . -
Split les répertoires dans une branche locale
#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2 -
Créer un vide quelque part repo. Nous supposons que nous avons créé un repo vide appelé sur GitHub qui
xyz
a chemin:git@github.com:simpliwp/xyz.git
-
Appuyez sur la nouvelle prise en pension.
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz git@github.com:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master
-
Cloner la prise en pension à distance nouvellement créé dans un nouveau répertoire local
#change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone git@github.com:simpliwp/xyz.git
Je recommande guide de GitHub à fendre les sous-dossiers dans un nouveau dépôt . Les étapes sont similaires à réponse de Paul , mais je trouve leurs instructions plus faciles à comprendre.
Je l'ai modifié les instructions afin qu'ils appliquent un dépôt local, au lieu d'un hébergé sur GitHub.
Fractionnement d'un sous-dossier sur en nouveau dépôt
Ouvrir Git Bash.
Changer le répertoire de travail en cours à l'endroit où vous souhaitez créer votre nouveau référentiel.
Clonage du référentiel contenant le sous-dossier.
git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
- Changer le répertoire de travail en cours dans votre dépôt cloné.
cd REPOSITORY-NAME
- Pour filtrer le sous-dossier du reste des fichiers dans le référentiel, exécutez
git filter-branch
, fournissant ces informations:
FOLDER-NAME
: Le dossier dans votre projet que vous souhaitez créer un dépôt séparé.
- Astuce:. Les utilisateurs de Windows doivent utiliser pour délimiter les dossiers
/
BRANCH-NAME
. La branche par défaut pour votre projet en cours, par exemple, oumaster
gh-pages
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME # Filter the specified branch in your directory and remove empty commits Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89) Ref 'refs/heads/BRANCH-NAME' was rewritten
Vous pourriez avoir besoin quelque chose comme « git reflog expire --expire Annule = maintenant --all » avant la collecte des ordures pour nettoyer effectivement les fichiers sur. git filtre branche supprime simplement les références dans l'histoire, mais ne supprime pas les entrées de reflog qui contiennent les données. Bien sûr, ce premier essai.
Mon utilisation du disque a chuté de façon spectaculaire en faisant cela, bien que mes conditions initiales étaient quelque peu différentes. Peut-être --subdirectory-filtre nie ce besoin, mais je doute.
Consultez projet git_split https://github.com/vangorra/git_split
Activer les répertoires git dans leurs propres référentiels dans leur propre emplacement. Pas de sous-arbre drôle d'affaires. Ce script prendra un répertoire existant dans votre dépôt git et transformer ce répertoire dans un dépôt indépendant de son propre. Sur le chemin, il copie sur toute l'histoire du changement pour le répertoire que vous avez fourni.
./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
src_repo - The source repo to pull from.
src_branch - The branch of the source repo to pull from. (usually master)
relative_dir_path - Relative path of the directory in the source repo to split.
dest_repo - The repo to push to.
Mettre cela dans votre gitconfig:
reduce-to-subfolder = !sh -c 'git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter cookbooks/unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --prune=now && git remote rm origin'
Je suis sous-arbre git sûr est tout beau et merveilleux, mais mes sous-répertoires de code managé git que je voulais aller était tout éclipsée. Donc, si vous utilisez egit, il est douloureusement facile. Prenez le projet que vous souhaitez déplacer et d'équipe> Se déconnecter, puis en équipe> partager au nouvel emplacement. Il sera par défaut d'essayer d'utiliser l'ancien emplacement des prises en pension, mais vous pouvez décocher la sélection de l'utilisation existante et choisir le nouveau lieu pour le déplacer. Tous egit de grêle.
J'ai trouvé la solution avant tout droit, L'idée est de copier référentiel, puis retirer une partie seulement inutile. Voici comment cela fonctionne:
1) Cloner un dépôt que vous souhaitez diviser
git clone git@git.thehost.io:testrepo/test.git
2) Déplacer vers un dossier git
cd test/
2) Supprimer les dossiers inutiles et commettre
rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'
3) Supprimer l'historique de forme de dossier inutile (s) avec BFG
cd ..
java -jar bfg.jar --delete-folders "{ABC}" test
cd test/
git reflog expire --expire=now --all && git gc --prune=now --aggressive
pour les dossiers se multiplient, vous pouvez utiliser des virgules
java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git
4) Vérifiez que l'histoire ne contient pas les fichiers / dossiers que vous venez de supprimer
git log --diff-filter=D --summary | grep delete
5) Vous avez maintenant référentiel propre sans ABC, si juste le pousser dans une nouvelle origine
remote add origin git@github.com:username/new_repo
git push -u origin master
Voilà. Vous pouvez répéter les étapes pour obtenir un autre dépôt,
il suffit de retirer XY1, XY2 et renommer XYZ -> ABC à l'étape 3
Vous pouvez facilement essayer https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/
Cela a fonctionné pour moi. Les questions que j'ai rencontrés dans les étapes indiquées ci-dessus sont
-
dans cette commande
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
LeBRANCH-NAME
est maître -
si la dernière étape échoue lors de la validation du fait de suivi de problème de protection - https://docs.gitlab.com/ee/user/project/protected_branches.html