J'ai un Git référentiel qui contient un certain nombre de sous-répertoires. Maintenant, j'ai constaté que l'un des sous-répertoires est indépendant de l'autre et doit être détaché dans un référentiel distinct.
Comment puis-je faire cela tout en conservant l'historique des fichiers dans le sous-répertoire?
Je suppose que je pourrais créer un clone et supprimer les parties indésirables de chaque clone, mais je suppose que cela me donnerait l’arborescence complète lors de la vérification d’une version plus ancienne, etc. Deux dépôts n'ont pas d'historique partagé.
Juste pour que ce soit clair, j'ai la structure suivante:
XYZ/
.git/
XY1/
ABC/
XY2/
Mais j'aimerais plutôt ceci:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
Mise à jour : ce processus est si commun que l'équipe git l'a simplifiée beaucoup plus facilement avec un nouvel outil, git subtree
. Voir ici: sous-répertoire Detach (move) dans un référentiel Git séparé
Vous souhaitez cloner votre référentiel, puis utiliser git filter-branch
pour tout marquer sauf le sous-répertoire que vous souhaitez dans votre nouveau référentiel.
Pour cloner votre référentiel local:
git clone /XYZ /ABC
(Remarque: le référentiel sera cloné à l'aide de liens physiques, mais ce n'est pas un problème car les fichiers 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 également réécrire, puis supprimons l’Origine pour éviter d’y appuyer et pour nous assurer 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 distantes:
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 voudrez peut-être aussi supprimer les étiquettes qui n’ont aucune relation avec le sous-projet; vous pouvez également le faire plus tard, mais vous devrez peut-être élaguer à nouveau votre rapport. Je ne l'ai pas fait et j'ai reçu un WARNING: Ref 'refs/tags/v0.1' is unchanged
pour toutes les balises (car elles n'étaient pas liées au sous-projet); de plus, après la suppression de telles balises, davantage d'espace sera récupéré. Apparemment, git filter-branch
devrait pouvoir réécrire d'autres balises, mais je n'ai pas pu le vérifier. Si vous souhaitez supprimer toutes les balises, utilisez git tag -l | xargs git tag -d
.
Ensuite, utilisez filter-branch and reset pour exclure les autres fichiers, afin qu’ils puissent être supprimés. Ajoutons également --tag-name-filter cat --Prune-empty
pour supprimer les commits vides et réécrire les balises (notez que cela devra effacer leur signature):
git filter-branch --tag-name-filter cat --Prune-empty --subdirectory-filter ABC -- --all
ou bien, réécrire uniquement la branche HEAD et ignorer les balises et autres branches:
git filter-branch --tag-name-filter cat --Prune-empty --subdirectory-filter ABC HEAD
Supprimez ensuite les modifications de sauvegarde afin que l'espace puisse être véritablement récupéré (bien que l'opération soit maintenant 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 tout son historique préservé.
Remarque: Pour la plupart des utilisations, git filter-branch
devrait en effet avoir le paramètre ajouté -- --all
. Oui c'est vraiment --space-- all
name__. Ce doit être le dernier paramètre de la commande. Comme Matli l'a découvert, les branches et les balises du projet sont incluses dans le nouveau référentiel.
Éditer: diverses suggestions issues des commentaires ci-dessous ont été incorporées pour s’assurer, par exemple, que le référentiel est réellement réduit (ce qui n’était pas toujours le cas auparavant).
Il s’avère que c’est une pratique tellement courante et utile que les seigneurs de git ont rendu la tâche vraiment facile, mais vous devez disposer d’une version plus récente de git (> = 1.7.11 mai 2012). Voir le appendix pour savoir comment installer le dernier git. De plus, il y a un exemple real-world dans la procédure pas à pas ci-dessous.
Préparer le vieux repo
pushd <big-repo>
git subtree split -P <name-of-folder> -b <name-of-new-branch>
popd
Remarque:<name-of-folder>
ne doit PAS contenir de caractères de début ou de fin. Par exemple, le dossier nommé subproject
DOIT être passé sous la forme subproject
, NOT ./subproject/
Remarque pour les utilisateurs de Windows: lorsque la profondeur de votre dossier est> 1, <name-of-folder>
doit comporter un séparateur de dossiers de style * nix (/). Par exemple, le dossier nommé path1\path2\subproject
DOIT être passé en tant que path1/path2/subproject
Créer le nouveau repo
mkdir <new-repo>
pushd <new-repo>
git init
git pull </path/to/big-repo> <name-of-new-branch>
Liez le nouveau repo à Github ou ailleurs
git remote add Origin <[email protected]:my-user/new-repo.git>
git Push Origin -u master
Nettoyage, si désiré
popd # get out of <new-repo>
pushd <big-repo>
git rm -rf <name-of-folder>
Note: toutes les références historiques sont conservées dans le référentiel. Reportez-vous à la Annexe ci-dessous si vous êtes vraiment préoccupé par la création d'un mot de passe ou si vous devez réduire la taille du fichier .git
.
...
Ce sont les mêmes étapes que ci-dessus, mais en suivant mes étapes exactes pour mon référentiel au lieu d'utiliser <meta-named-things>
.
Voici un projet que j'ai pour implémenter 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 souhaite séparer un seul dossier, btoa
, dans un référentiel git distinct
pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd
J'ai maintenant une nouvelle branche, btoa-only
, qui n'a validé que pour btoa
et je veux 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 dépôt sur Github ou bitbucket, ou quoi que ce soit, et l'ajoute à la variable Origin
(d'ailleurs, "Origin" est simplement une convention, pas une partie de la commande - vous pouvez l'appeler "serveur distant" ou ce que vous aimez).
git remote add Origin [email protected]:node-browser-compat/btoa.git
git Push Origin -u master
Bonne journée!
Remarque: Si vous avez créé un dépôt avec README.md
, .gitignore
et LICENSE
, vous devez d'abord extraire:
git pull Origin -u master
git Push Origin -u master
Enfin, je veux supprimer le dossier du dépôt principal
git rm -rf btoa
...
Pour obtenir la dernière version de git:
brew install git
Pour obtenir une infusion pour OS X:
Sudo apt-get update
Sudo apt-get install git
git --version
Si cela ne fonctionne pas (vous avez une très ancienne version d'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.
Par défaut, supprimer des fichiers de git ne les supprime pas réellement, cela signifie simplement qu'ils ne sont plus là. Si vous voulez réellement supprimer les références historiques (c'est-à-dire que vous avez un mot de passe validé), procédez comme suit:
git filter-branch --Prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD
Après cela, vous pouvez vérifier que votre fichier ou dossier n'apparaît plus du tout dans l'historique git.
git log -- <name-of-folder> # should show nothing
Cependant, vous ne pouvez pas "Pousser" les suppressions dans github, etc. Si vous essayez, vous obtiendrez une erreur et vous devrez git pull
avant de pouvoir git Push
- et vous reviendrez alors à tout avoir dans votre historique.
Donc, si vous souhaitez supprimer l'historique de "l'origine", c'est-à-dire le supprimer de github, bitbucket, etc., vous devrez supprimer le référentiel et ré-envoyer une copie de ce dernier au format. Mais attendez - il y a plus! - Si vous souhaitez vraiment vous débarrasser d'un mot de passe ou de quelque chose du genre, vous devez modifier la sauvegarde (voir ci-dessous).
.git
plus petitLa commande de suppression de l'historique mentionnée ci-dessus laisse encore un tas de fichiers de sauvegarde, car git est très gentil pour vous aider à ne pas ruiner votre repo par accident. Il supprimera éventuellement les fichiers orphelins au fil des jours et des mois, mais les conservera pendant un certain temps au cas où vous réaliseriez que vous avez supprimé accidentellement quelque chose que vous ne vouliez pas.
Donc si vous voulez vraiment vider la corbeille pour réduire immédiatement la taille du clone d'un dépôt, vous devez faire tout ce travail 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 suivre ces étapes, sauf si vous savez que vous devez le faire - juste au cas où vous élagueriez le mauvais sous-répertoire, vous savez? Les fichiers de sauvegarde ne doivent pas être clonés lorsque vous appuyez sur le référentiel, ils seront simplement dans votre copie locale.
La réponse de Paul crée un nouveau référentiel contenant/ABC, mais ne supprime pas/ABC de/XYZ. La commande suivante supprimera/ABC de/XYZ:
git filter-branch --tree-filter "rm -rf ABC" --Prune-empty HEAD
Bien sûr, testez-le d'abord dans un référentiel 'clone --no-hardlinks' et suivez-le avec les listes de Paul de reset, gc et Prune.
J'ai constaté que pour supprimer correctement l'ancien historique du nouveau référentiel, vous devez effectuer 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
Supprimez toutes les références à l'ancienne histoire. "Origin" gardait une trace de votre clone, et "original" est l'endroit où filter-branch enregistre l'ancien:
git remote rm Origin
git update-ref -d refs/original/refs/heads/master
git reflog expire --expire=now --all
Même maintenant, votre historique pourrait être bloquée dans un fichier pack que fsck ne touchera pas. Déchirez-le en lambeaux, créez un nouveau fichier pack et supprimez les objets inutilisés:
git repack -ad
Il y a une explication de ceci dans le manuel pour le filtre-branche .
Modifier: script Bash ajouté.
Les réponses données ici ne fonctionnaient que partiellement pour moi; Beaucoup de gros fichiers sont restés dans la mémoire cache. Ce qui a finalement fonctionné (après des heures dans #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 Mo. Celui-ci l'a ramené à 1,7 MB. Peut-être que ça 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 n'est plus si complexe que vous pouvez simplement utiliser la commande git filter-branch sur un clone de votre référentiel pour supprimer les sous-répertoires que vous ne voulez pas, puis transférer vers la nouvelle télécommande.
git filter-branch --Prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git Push <MY_NEW_REMOTE_URL> -f .
Update: le module git-subtree était si utile que l'équipe git l'a intégré au noyau et l'a rendu git subtree
. Voir ici: Détachez (déplacez) le sous-répertoire dans un référentiel Git séparé
git-subtree peut être utile pour cela
http://github.com/apenwarr/git-subtree/blob/master/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 ™" answer afin de scinder plusieurs sous-dossiers (disons sub1
et sub2
) dans un nouveau référentiel git.
Préparer le vieux 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 doit PAS contenir de caractères de début ou de fin. Par exemple, le dossier nommé subproject
DOIT être passé sous la forme subproject
, NOT ./subproject/
Remarque pour les utilisateurs de Windows: lorsque la profondeur de votre dossier est> 1, <name-of-folder>
doit comporter un séparateur de dossiers de style * nix (/). Par exemple, le dossier nommé path1\path2\subproject
DOIT être passé en tant que path1/path2/subproject
. De plus, n'utilisez pas mv
command mais move
.
Note finale: l'unique et grande différence avec la réponse de base est la deuxième ligne du script "git filter-branch...
"
Créer le nouveau repo
mkdir <new-repo>
pushd <new-repo>
git init
git pull </path/to/big-repo> <name-of-new-branch>
Liez le nouveau repo à Github ou ailleurs
git remote add Origin <[email protected]:my-user/new-repo.git>
git Push Origin -u master
Nettoyage, si désiré
popd # get out of <new-repo>
pushd <big-repo>
git rm -rf <name-of-folder>
Note: cela laisse toutes les références historiques dans le référentiel. Voir le Annexe dans la réponse d'origine si vous êtes réellement préoccupé par la saisie d'un mot de passe ou si vous devez réduire la taille du fichier .git
. .
La question initiale veut que les fichiers XYZ/ABC/(*) deviennent ABC/ABC/(*). Après avoir implémenté la réponse acceptée pour mon propre code, j'ai remarqué que cela transforme réellement XYZ/ABC/(* fichiers) en ABC/(* fichiers). La page de manuel filter-branch dit même:
Le résultat contiendra ce répertoire (et seulement celui-là) en tant que racine du projet . "
En d’autres termes, le dossier de niveau supérieur est "promu" d’un niveau. C'est une distinction importante car, par exemple, dans mon historique, j'avais renommé un dossier de niveau supérieur. En promouvant les dossiers "up" d'un niveau, git perd la continuité au commit où je l'ai renommé.
Ma réponse à la question est alors de faire 2 copies du référentiel et de supprimer manuellement le ou les dossiers que vous souhaitez conserver dans chacun. La page de manuel me soutient avec ceci:
[...] évitez d'utiliser [cette commande] si un simple commit suffit à résoudre votre problème
Pour ajouter à la réponse de Paul , j'ai trouvé que pour récupérer de l'espace, je dois pousser HEAD dans un référentiel propre et réduire la taille du répertoire .git/objects/pack.
c'est à dire.
$ mkdir ... ABC.git $ cd ... ABC.git $ git init --bare
Après le gc Prune, faites aussi:
$ git Push ... ABC.git HEAD
Alors tu peux faire
$ git clone ... ABC.git
et la taille de ABC/.git est réduite
En fait, certaines étapes fastidieuses (par exemple, git gc) ne sont pas nécessaires avec le référentiel Push to clean, à savoir:
$ git clone --no-hardlinks/XYZ /ABC $ git filtre-branche - sous-répertoire-filtre ABC HEAD $ git reset --hard $ git Push ... ABC. git HEAD
La manière correcte est maintenant la suivante:
git filter-branch --Prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
GitHub a même maintenant un petit article sur de tels cas.
Mais assurez-vous de cloner d'abord votre référentiel d'origine dans un répertoire séparé (car cela supprimerait tous les fichiers et autres répertoires et vous auriez probablement besoin de les utiliser).
Donc, votre algorithme devrait être:
git filter-branch
, il ne restait que des fichiers dans un sous-répertoire, Push to new remoteIl semble que la plupart (toutes?) Des réponses ici reposent sur une forme de git filter-branch --subdirectory-filter
et ses semblables. Cela peut fonctionner "la plupart du temps", cependant, dans certains cas, par exemple lorsque vous avez renommé le dossier, par exemple:
ABC/
/move_this_dir # did some work here, then renamed it to
ABC/
/move_this_dir_renamed
Si vous effectuez un style de filtre git normal pour extraire "move_me_renamed", vous perdrez l'historique des modifications de fichiers survenu depuis la date initiale de move_this_dir ( ref ).
Il semble donc que le seul moyen de conserver réellement l'historique des modifications de all (si votre cas est semblable à celui-ci) consiste essentiellement à copier le référentiel (créer un nouveau référentiel, définissant ainsi l'origine), puis tout le reste et renommez le sous-répertoire en parent comme ceci:
git branch -a
git checkout --track Origin/branchABC
cp -r oldmultimod simple
cd simple
git rm otherModule1 other2 other3
git mv moduleSubdir1/* .
rmdir moduleSubdir1
git status
git remote set-url Origin http://mygithost:8080/git/our-splitted-module-repo
git remote -v
git Push
git checkout branch2
Ceci suit le document github "Diviser un sous-dossier dans un nouveau référentiel" étapes 6 à 11 pour pousser le module dans un nouveau référentiel.
Cela ne vous épargnera aucun espace dans votre dossier .git, mais conservera tout l'historique de vos modifications pour ces fichiers, même après les avoir renommés. Et cela ne vaut peut-être pas la peine s'il n'y a pas "beaucoup" d'histoire perdue, etc. Mais au moins, vous êtes assuré de ne pas perdre d'anciens commits!
J'ai eu exactement ce problème, mais toutes les solutions standard basées sur git filter-branch étaient extrêmement lentes. Si vous avez un petit référentiel, alors ce n'est peut-être pas un problème, c'était pour moi. J'ai écrit un autre programme de filtrage git basé sur libgit2 qui, dans un premier temps, crée des branches pour chaque filtrage du référentiel principal, puis les pousse pour nettoyer les référentiels à l'étape suivante. Sur mon référentiel (500Mo 100000 validés), les méthodes standard de branchement de filtres git prenaient des 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 que c'est utile à quelqu'un.
Voici comment utiliser GitHub sur une machine Windows. Supposons que vous ayez un référentiel cloné en résidant dans C:\dir1
. La structure du répertoire ressemble à ceci: C:\dir1\dir2\dir3
. Le répertoire dir3
est celui que je veux être un nouveau dépôt séparé.
Github:
MyTeam/mynewrepo
Invite Bash:
$ cd c:/Dir1
$ git filter-branch --Prune-empty --subdirectory-filter dir2/dir3 HEAD
Renvoyé: Ref 'refs/heads/master' was rewritten
(fyi: dir2/dir3 est sensible à la casse.)
$ git remote add some_name [email protected]:MyTeam/mynewrepo.git
git remote add Origin etc
. n'a pas fonctionné, a renvoyé "remote Origin already exists
"
$ git Push --progress some_name master
git splits
. Je l'ai créé comme une extension git, basée sur la solution de jkeating . Fractionner 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éez un dépôt vide quelque part. Nous supposerons que nous avons créé un dépôt vide appelé xyz
sur GitHub qui a le chemin suivant: [email protected]:simpliwp/xyz.git
Appuyez sur le nouveau repo .
#add a new remote Origin for the empty repo so we can Push to the empty repo on GitHub
git remote add Origin_xyz [email protected]:simpliwp/xyz.git
#Push the branch to the empty repo's master branch
git Push Origin_xyz XYZ:master
Cloner le référentiel distant 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 [email protected]:simpliwp/xyz.git
Utilisez cette commande de filtrage pour supprimer un sous-répertoire tout en préservant vos balises et branches:
git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --Prune-empty \
--tag-name-filter cat -- --all
Je recommande le guide de GitHub pour fractionner les sous-dossiers dans un nouveau référentiel . Les étapes sont similaires à réponse de Paul , mais j'ai trouvé leurs instructions plus faciles à comprendre.
J'ai modifié les instructions pour qu'elles s'appliquent à un référentiel local plutôt qu'à un hébergeur sur GitHub.
Division d'un sous-dossier dans un nouveau référentiel
Ouvrez Git Bash.
Modifiez le répertoire de travail actuel à l'emplacement où vous souhaitez créer votre nouveau référentiel.
Clonez le référentiel contenant le sous-dossier.
git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
- Changez le répertoire de travail actuel dans votre référentiel cloné.
cd REPOSITORY-NAME
- Pour filtrer le sous-dossier du reste des fichiers du référentiel, exécutez
git filter-branch
en fournissant les informations suivantes:
FOLDER-NAME
: le dossier de votre projet dans lequel vous souhaitez créer un référentiel distinct de .
- Conseil: Les utilisateurs Windows doivent utiliser
/
pour délimiter des dossiers.BRANCH-NAME
: branche par défaut de votre projet actuel, par exemple,master
ough-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
Comme je mentionné ci-dessus , je devais utiliser la solution inverse (supprimer tous les commits ne touchant pas mon dir/subdir/targetdir
) qui semblait fonctionner plutôt bien en supprimant environ 95% des commits (comme vous le souhaitez). Il reste cependant deux petits problèmes.
FIRST, filter-branch
a fait un travail remarquable en supprimant les validations qui introduisent ou modifient le code, mais apparemment, fusions validées se trouvent sous sa position dans le Gitivers.
C’est un problème esthétique avec lequel je peux probablement vivre (dit-il… reculant lentement, les yeux écartés) .
SECONDE les quelques commits qui restent sont à peu près ALL dupliqués! Il me semble avoir acquis une deuxième chronologie redondante 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 succursales locales ne sont pas toutes sur la même chronologie (ce qui explique certainement pourquoi elle existe et ne consiste pas seulement en une récupération de déchets).
La seule chose que je puisse imaginer, c’est que l’un des commits supprimés était, peut-être, le commit de la fusion unique que filter-branch
a effectivement supprimé , et qui a créé le montage parallèle chaque brin maintenant non fusionné a pris sa propre copie des commits. ( haussement d'épaules Où est mon TARDiS?) Je suis à peu près sûr de pouvoir régler ce problème, bien que j'adore vraiment comprendre comment cela s'est passé.
Dans le cas de la folle mergefest-O-RAMA, je vais probablement laisser celle-ci seule, car elle est si fermement ancrée dans mon histoire de commit (me menaçant chaque fois que je m'approche), elle ne semble pas réellement causer aucun problème non esthétique et parce qu'il est assez joli dans Tower.app.
Vous aurez peut-être besoin de quelque chose comme "git reflog expire --expire = now --all" avant la récupération de place pour nettoyer les fichiers. git filter-branch supprime simplement les références dans l'historique, mais ne supprime pas les entrées de reflog contenant les données. Bien sûr, testez ceci en premier.
Mon utilisation du disque a considérablement chuté, même si mes conditions initiales étaient quelque peu différentes. Peut-être que --subdirectory-filter annule ce besoin, mais j'en doute.
Découvrez le projet git_split à https://github.com/vangorra/git_split
Transformez les répertoires git en leurs propres référentiels, à leur propre emplacement. Aucune sous-affaire drôle. Ce script utilisera un répertoire existant dans votre référentiel git et transformera ce répertoire en un référentiel indépendant. En cours de route, il copiera l’ensemble de l’historique des modifications du répertoire 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.
Mettez ceci 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 sûr que git sous-arbre est parfait et merveilleux, mais mes sous-répertoires de code géré par git que je voulais déplacer étaient tous dans Eclipse . Donc, si vous utilisez egit, c’est terriblement facile . vous voulez déplacer et équipe-> déconnectez-le, puis équipe-> partagez-le au nouvel emplacement. Il essaiera par défaut d’utiliser l’ancien emplacement du référentiel, mais vous pourrez décocher la sélection existante et utiliser le nouvel emplacement pour le déplacer.
Vous pouvez facilement essayer le https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/
Cela a fonctionné pour moi. Les problèmes que j'ai rencontrés dans les étapes ci-dessus sont
dans cette commande git filter-branch --Prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
Le BRANCH-NAME
est maître
si la dernière étape échoue lors de la validation en raison d’un problème de protection, suivez - https://docs.gitlab.com/ee/user/project/protected_branches.html
J'ai trouvé une solution assez simple. L'idée est de copier le référentiel puis de supprimer les parties inutiles. Voilà comment cela fonctionne:
1) Clonez un référentiel que vous souhaitez scinder
git clone [email protected]:testrepo/test.git
2) Déplacer vers le dossier git
cd test/
2) Supprimer les dossiers inutiles et le commettre
rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'
3) Supprimez l’historique de la forme des dossiers inutiles 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 multiplier les dossiers, vous pouvez utiliser une virgule
Java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git
4) Vérifiez que l'historique ne contient pas les fichiers/dossiers que vous venez de supprimer
git log --diff-filter=D --summary | grep delete
5) Maintenant, vous avez un référentiel propre sans ABC, alors il suffit de le pousser dans la nouvelle origine
remote add Origin [email protected]:username/new_repo
git Push -u Origin master
C'est tout. Vous pouvez répéter les étapes pour obtenir un autre référentiel,
il suffit de supprimer XY1, XY2 et de renommer XYZ -> ABC à l'étape 3