Détacher (déplacer) le sous-répertoire dans un dépôt git séparé

j'ai un dépôt Git qui contient un certain nombre de sous-répertoires. Maintenant, j'ai trouvé que l'un des sous-répertoires est pas lié à l'autre et doivent être détachés dans un autre référentiel.

Comment puis-je faire cela tout en gardant l'historique 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 quand vérifier une révision plus ancienne, etc. Cela pourrait être acceptable, mais je préférerais pouvoir prétendre que les deux dépôts n'ont pas une histoire commune.

juste pour être clair, j'ai la structure suivante:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

mais je voudrais plutôt ceci:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/
1607
demandé sur Nick Volynkin 2008-12-11 16:57:03

22 réponses

Update : ce processus est si courant, que l'équipe git l'a simplifié avec un nouvel outil, git subtree . Voir ici: Détacher (se déplacer) sous-répertoire en séparer dépôt Git


Vous voulez cloner votre dépôt et ensuite utiliser git filter-branch pour marquer tout, mais le sous-répertoire que vous voulez dans votre nouveau repo être récupérées.

  1. pour cloner votre dépôt local:

    git clone /XYZ /ABC
    

    (Note: le dépôt sera cloné à l'aide de liens durs, mais ce n'est pas un problème puisque les fichiers reliés ne seront pas modifiés en eux-mêmes-de nouveaux seront créés.)

  2. maintenant, préservons les branches intéressantes que nous voulons réécrire aussi bien, et puis enlever l'origine pour éviter d'y pousser et pour s'assurer que les vieilles commits ne seront pas référencé 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 éloignées:

    cd /ABC
    for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
    git remote rm origin
    
  3. Maintenant, vous pourriez vouloir également supprimer les étiquettes qui n'ont pas de relation avec le sous-projet; vous pouvez également le faire plus tard, mais vous pourriez avoir besoin de tailler votre repo à nouveau. Je ne l'ai pas fait et j'ai obtenu un WARNING: Ref 'refs/tags/v0.1' is unchanged pour toutes les étiquettes (puisqu'elles étaient toutes sans rapport avec le sous-projet); en outre, après avoir enlevé ces étiquettes plus d'espace sera récupéré. Apparemment git filter-branch devrait être capable de réécrire d'autres tags, mais je n'ai pas pu le vérifier. Si vous voulez supprimer toutes les étiquettes, utilisez git tag -l | xargs git tag -d .

  4. ensuite, utilisez la branche de filtre et réinitialiser pour exclure les autres fichiers, afin qu'ils puissent être élagués. Ajoutons aussi --tag-name-filter cat --prune-empty pour supprimer les propagations vides et réécrire les tags (notez que cela devra supprimer leur signature):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    

    ou bien, pour réécrire uniquement la tête branche et ignorer tags et autres branches:

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
    
  5. puis supprimer les réflogs de sauvegarde afin que l'espace puisse être vraiment récupéré (bien que maintenant l'opération soit 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, git filter-branch devrait en effet avoir le paramètre ajouté -- --all . Oui, c'est vraiment - - l'espace - - all . Ceci doit être le dernier paramètre de la commande. Comme Matli l'a découvert, cela maintient les branches de projet et les tags inclus dans le nouveau repo.

éditer: diverses suggestions des commentaires ci-dessous ont été incorporés pour s'assurer, par exemple, que le dépôt est effectivement réduction (ce qui n'était pas toujours le cas avant).

1159
répondu Paul 2018-06-20 22:57:50

La Voie De La Facilité™

il s'avère que c'est une pratique si commune et utile que les overlords de git l'ont rendue vraiment facile, mais vous devez avoir une nouvelle version de git (>= 1.7.11 mai 2012). Voir le annexe pour savoir comment installer le dernier git. Aussi, il y a un exemple du monde réel dans le walkthrough ci-dessous.

  1. préparer la old repo

    pushd <big-repo>
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    Note: <name-of-folder> ne doit pas contenir de caractères principaux ou secondaires. Par exemple, le dossier nommé subproject doit être passé comme subproject , pas ./subproject/

    Note pour les utilisateurs de windows: lorsque la profondeur de votre dossier est > 1, <name-of-folder> doit avoir un séparateur de dossier de style nix (/). Par exemple, le dossier nommé path1\path2\subproject doit être passé comme path1/path2/subproject

  2. Créer le nouveau repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. reliez le nouveau repo à Github ou n'importe où

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. 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 dépôt.Voir appendice ci-dessous si vous êtes en fait préoccupé d'avoir commis un mot de passe ou vous avez besoin de diminuer la taille du fichier de votre dossier .git .

...

Walkthrough

ce sont les mêmes étapes que ci-dessus , mais en suivant mes étapes exactes pour mon dépôt au lieu d'utiliser <meta-named-things> .

voici un projet que j'ai pour implémenter JavaScript browser modules dans le noeud:

tree ~/Code/node-browser-compat

node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator

je veux séparer un seul dossier, btoa , en 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, btoa-only , qui n'a que des commits pour btoa et je veux créer un nouveau dépôt.

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 quoi que ce soit, et je l'ajoute c'est le origin (btw, "origin" est juste une convention, pas une partie de la commande - vous pouvez l'appeler "remote-server" ou ce que vous voulez)

git remote add origin git@github.com:node-browser-compat/btoa.git
git push origin -u master

bonne journée!

Note: si vous avez créé une pension avec un README.md , .gitignore et LICENSE , vous devrez tirer en premier:

git pull origin -u master
git push origin -u master

enfin, je vais vouloir supprimer le dossier de la plus grande pension

git rm -rf btoa

...

appendice

dernière version sur OS X

pour obtenir la dernière version de git:

brew install git

pour obtenir brew pour OS X:

http://brew.sh

dernière version sur Ubuntu

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 ça ne marche 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

grâce à rui.araujo des commentaires.

effacer votre histoire

par défaut Supprimer des fichiers de git ne les supprime pas réellement de git, il s'engage simplement qu'ils ne sont plus là. Si vous voulez réellement supprimer les références historiques (i.e. vous avez un mot de passe engagé), vous devez le faire:

git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD

Après cela, vous pouvez vérifier que votre fichier ou folder n'apparaît plus du tout dans l'historique git

git log -- <name-of-folder> # should show nothing

Cependant, vous ne peut pas "pousser" les suppressions de github et ainsi de suite. Si vous essayez, vous obtiendrez une erreur et vous devrez git pull avant de pouvoir git push - et alors vous êtes de retour à avoir tout dans votre histoire.

donc si vous voulez supprimer l'histoire de la "Origine" - ce qui signifie de le supprimer de GitHub, bitbucket, etc - vous aurez besoin de supprimer le repo et re-pousser un taillés copie du repo. Mais attendez - il y a plus ! - Si vous êtes vraiment soucieux de se débarrasser d'un mot de passe ou quelque chose comme ça, vous aurez besoin de tailler la sauvegarde (voir ci-dessous).

faire .git petits

la commande delete history mentionnée ci - dessus laisse encore un tas de fichiers de sauvegarde-parce que git est trop aimable pour vous aider à ne pas ruiner votre repo par accident. Il éventuellement supprimé les fichiers orphelins au cours des jours et des mois, mais il les laisse là pendant un certain temps au cas où vous réalisez que vous accidentellement supprimé quelque chose que vous ne vouliez pas.

donc si vous voulez vraiment vider la poubelle à réduire la taille du clone d'une pension immédiatement vous devez faire tout ce truc 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 recommande de ne pas effectuer ces étapes sauf si tu sais que tu dois ... juste au cas où tu as taillé le mauvais sous - répertoire, tu sais? Les fichiers de sauvegarde ne devraient pas être clonés quand vous appuyez sur la mise en veille, ils seront juste dans votre copie locale.

crédit

1138
répondu CoolAJ86 2017-05-23 11:47:26

Paul's answer crée un nouveau dépôt contenant /ABC, mais ne supprime pas /ABC de l'intérieur /XYZ. La commande suivante supprimera / ABC de / XYZ:

git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD

bien sûr, testez-le dans un dépôt 'clone --no-hardlinks' en premier, et suivez-le avec les commandes reset, gc et prune Paul listes.

131
répondu pgs 2017-05-23 12:18:26

j'ai trouvé que pour correctement supprimer l'ancienne histoire du nouveau dépôt, vous devez faire un peu plus de travail après l'étape filter-branch .

  1. Faire le clone et le filtre:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. Supprimer toute référence à l'histoire ancienne. "origin" gardait la trace de votre clone, et "original" est où filter-branch sauve les vieux trucs:

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. même maintenant, votre histoire pourrait être coincée dans un fichier que fsck ne touchera pas. Déchirez - le en lambeaux, en créant un nouveau fichier pack et en supprimant les objets inutilisés:

    git repack -ad
    

Il y a , une explication de ce dans le manuel pour filter-branch .

94
répondu Josh Lee 2011-01-05 18:18:29

Edit: script Bash ajouté.

les réponses données ici n'ont fonctionné que partiellement pour moi; beaucoup de gros fichiers sont restés dans le cache. Ce qui a finalement fonctionné (après les 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 dépôt était d'environ 100 MB. Celui-ci l'a ramené à 1,7 mo. Peut-être que ça aide quelqu'un :)


Le script bash suivant automatise la tâche:

!/bin/bash

if (( $# < 3 ))
then
    echo "Usage:   "151910920" </path/to/repo/> <directory/to/extract/> <newName>"
    echo
    echo "Example: "151910920" /Projects/42.git first/answer/ firstAnswer"
    exit 1
fi


clone=/tmp/Clone
newN=/tmp/

git clone --no-hardlinks file:// ${clone}
cd ${clone}

git filter-branch --subdirectory-filter   --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
38
répondu Simon A. Eugster 2015-04-11 14:00:08

ce n'est plus aussi complexe vous pouvez simplement utiliser la commande git filter-branch sur un clone de vous repo pour sélectionner les sous-répertoires que vous ne voulez pas et puis pousser sur la nouvelle télécommande.

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .
21
répondu jeremyjjbrown 2015-04-20 18:43:21

Update : le module git-subtree était tellement utile que l'équipe git l'a tiré dans le noyau et l'a fait git subtree . Voir ici: Détacher (se déplacer) sous-répertoire en séparer dépôt Git

git-sous-arborescence peut être utile pour cette

http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (déprécié)

http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree /

19
répondu D W 2017-05-23 12:18:26

Voici une petite modification de CoolAJ86 's "the Easy Way™" answer afin de scinder multiple folders sub (disons sub1 et sub2 ) en un nouveau dépôt git.

la Voie de La facilité™ (plusieurs sous-dossiers)

  1. 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
    

    Note: <name-of-folder> ne doit pas contenir de caractères principaux ou secondaires. Par exemple, le dossier nommé subproject doit être passé comme subproject , pas ./subproject/

    Note pour les utilisateurs de windows: lorsque la profondeur de votre dossier est > 1, <name-of-folder> doit avoir un séparateur de dossier *nix style (/). Par exemple, le dossier nommé path1\path2\subproject doit être passé comme path1/path2/subproject . De plus, n'utilisez pas la commande mv mais move .

    note finale: la différence unique et grande avec la réponse de base est la deuxième ligne du script " git filter-branch... "

  2. Créer le nouveau repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. reliez le nouveau repo à Github ou n'importe où

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. Nettoyage", si désiré

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    Note : il reste toutes les références historiques dans le dépôt.Voir le annexe dans la réponse originale si vous êtes réellement préoccupé d'avoir commis un mot de passe ou si vous avez besoin de diminuer la taille du fichier de votre dossier .git .

13
répondu Anthony O. 2017-05-23 12:26:37

la question initiale veut que XYZ/ABC/(*files) devienne ABC/ABC/(*files). Après avoir implémenté la réponse acceptée pour mon propre code, j'ai remarqué qu'elle change en fait XYZ/ABC/(*files) en ABC/(*files). La page de manuel filter-branch dit même,

le résultat contiendra ce répertoire (et seulement cela) comme sa racine de projet ."

En d'autres termes, il favorise le dossier de niveau supérieur "" niveau. C'est une distinction importante parce que, par exemple, dans mon histoire, j'avais renommé un dossier de niveau supérieur. En faisant la promotion de dossiers "up" un niveau, git perd la continuité à la propagation où j'ai fait le renommage.

I lost contiuity after filter-branch

ma réponse à la question est alors de faire 2 copies du dépôt et supprimer manuellement le(S) dossier (s) que vous voulez garder dans chacun. La page de manuel me soutient avec ceci:

[...] évitez d'utiliser [cette commande] si une simple commit suffit à résoudre votre problème

11
répondu MM. 2012-04-17 05:12:06

pour ajouter à la réponse de Paul , j'ai trouvé que pour finalement récupérer de l'espace, je dois pousser la tête à un dépôt propre et qui diminue la taille de la .git/objects/pack répertoire.

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 vous pouvez faire

$ git clone ...ABC.git

et la taille de ABC/.réduction de git 151970920"

en fait, certains de les étapes chronophages (par ex. git gc) ne sont pas nécessaires avec la pression pour nettoyer le 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
7
répondu Case Larsen 2017-05-23 12:10:41

la bonne voie est maintenant la suivante:

git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub ont maintenant même petit article sur de tels cas.

mais assurez-vous de cloner votre repo d'origine pour séparer le répertoire en premier (comme il supprimerait tous les fichiers et les autres répertoires et vous avez probablement besoin de travailler avec eux).

donc votre algorithme devrait être:

  1. clonez votre distance repo à un autre répertoire
  2. utilisant git filter-branch n'a laissé que des fichiers sous un sous-répertoire, push à New remote
  3. créer engageons à supprimer ce sous-répertoire de votre télécommande d'origine repo
5
répondu Olexandr Shapovalov 2014-11-12 13:22:04

Il semble que la plupart (toutes?) des réponses ici s'appuient sur une certaine forme de git filter-branch --subdirectory-filter et de ses semblables. Cela peut fonctionner "la plupart du temps" Cependant pour certains cas, par exemple le cas de 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 normal pour extraire" move_me_renamed "vous perdrez l'historique de changement de fichier qui s'est produit de dos quand il a été initialement move_this_dir ( ref ).

il ainsi il semble que la seule façon de vraiment garder tout l'histoire de changement (si la vôtre est un cas comme celui-ci), est, en essence, de copier le dépôt (créer un nouveau repo, définir que d'être l'origine), puis tout le reste nuke et renommer le sous-répertoire au parent comme ceci:

  1. cloner le projet multi-modules localement
  2. Branches-vérifier ce qui est là: git branch -a
  3. faire une caisse à chaque branche à inclure dans le fractionnement pour obtenir une copie locale sur votre poste de travail: git checkout --track origin/branchABC
  4. Faire une copie dans un nouveau répertoire: cp -r oldmultimod simple
  5. allez dans la nouvelle copie du projet: cd simple
  6. se débarrasser des autres modules qui ne sont pas nécessaires dans ce projet:
  7. git rm otherModule1 other2 other3
  8. Maintenant seul le sous-DIR du module cible reste
  9. se débarrasser du module subdiviser de sorte que la racine du module devienne la nouvelle racine du projet
  10. git mv moduleSubdir1/* .
  11. supprimer la relique: rmdir moduleSubdir1
  12. vérifier les changements en tout point: git status
  13. créer la nouvelle git repo et copier son URL pour pointer ce projet en elle:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. vérifier que c'est bien: git remote -v
  16. Pousser les modifications jusqu'à la distance repo: git push
  17. allez au rapport à distance et vérifiez que tout est là
  18. répéter pour toute autre branche nécessaire: git checkout branch2

Ce qui suit le github doc "Fractionnement d'un sous-dossier dans un nouveau référentiel" les étapes 6 à 11 pour pousser le module à un nouveau repo.

cela ne vous épargnera pas de place dans votre .dossier git, mais il préservera tous vos changez l'historique pour ces fichiers, même à travers les renommages. Et cela peut ne pas valoir la peine s'il n'y a pas "beaucoup" d'histoire perdue, etc. Mais au moins vous êtes garanti de ne pas perdre plus vieux commits!

5
répondu rogerdpack 2017-10-31 10:41:55

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 c'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 dépôt primaire et les pousse ensuite à nettoyer les dépôts comme étape suivante. Sur mon dépôt (500MB 100000 commits) les méthodes standard git filter-branch ont pris des jours. Mon le programme prend des 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.

4
répondu slobobaby 2014-03-10 17:39:13

pour ce que ça vaut, voici comment utiliser GitHub sur une machine Windows. Disons que vous avez un rapport cloné dans C:\dir1 . La structure du répertoire ressemble à ceci: C:\dir1\dir2\dir3 . Le dir3 répertoire est celui que je veux être un nouveau repo.

Github:

  1. créez votre nouveau dépôt: MyTeam/mynewrepo

Invite Bash:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD

    Retourné: Ref 'refs/heads/master' was rewritten (pour information: dir2/dir3 est sensible à la casse.)

  3. $ git remote add some_name git@github.com:MyTeam/mynewrepo.git

    git remote add origin etc . n'a pas fonctionné, retourné " remote origin already exists "

  4. $ git push --progress some_name master

4
répondu James Lawruk 2015-03-06 01:26:14

Comme je l' mentionné ci-dessus , j'ai dû utiliser l'inverse de la solution (suppression de tous les s'engage à ne pas toucher à mon dir/subdir/targetdir ) qui semblait fonctionner assez bien en retrait d'environ 95% de la commet (comme souhaité). Il reste toutefois deux petites questions à régler.

PREMIÈRE , filter-branch a fait un bang à l'emploi de retrait qui s'engage introduire ou de modifier le code, mais apparemment, fusion s'engage sont au-dessous de sa gare dans le Gitiverse.

C'est un problème esthétique que je peux probablement vivre avec (dit-il...la sauvegarde doucement avec les yeux évitée) .

DEUXIÈME les quelques commits qui restent sont assez bien TOUS dupliqués! Il semble que j'ai acquis une deuxièmement, un 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 toutes sur la même ligne de temps (ce qui est, certainement pourquoi il existe et n'est pas seulement des ordures collectées).

La seule chose que je peux imaginons que l'un des commits supprimés était, peut-être, la seule commit de fusion que filter-branch effectivement supprimé , et qui a créé la ligne de temps parallèle que chaque maintenant-toron non fusionné a pris sa propre copie des commits. ( shrug Où est mon TARDiS?) Je suis assez sûr que je peux résoudre ce problème, bien que je vraiment j'aimerais comprendre comment c'est arrivé.

dans le cas de crazy mergefest-O-RAMA, je vais probablement en laissant celui-ci seul puisqu'il s'est si fermement enraciné dans mon histoire de commit-menaçant à moi chaque fois que je m'approche -, il ne semble pas être en train de causer des problèmes non-cosmétiques et parce qu'il est assez joli dans la Tour.App.

3
répondu Jay Allen 2017-05-23 12:18:26

utilisez cette commande filter pour supprimer un sous-répertoire, tout en préservant vos tags et branches:

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
3
répondu cmcginty 2014-05-26 14:51:21

La Façon La Plus Facile

  1. installer git splits . Je l'ai créé comme une extension git, basé sur solution de jkeating .
  2. #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

  3. créer un repo vide quelque part. Nous supposerons que nous avons créé un repo vide appelé xyz sur GitHub qui a le chemin: git@github.com:simpliwp/xyz.git

  4. Pousser vers 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 git@github.com:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master

  5. cloner la nouvelle mise à distance repo 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

3
répondu AndrewD 2017-05-23 12:18:26

vous pourriez avoir besoin de quelque chose comme" git reflog expire --expire=now --all " avant la collecte des ordures pour réellement nettoyer les fichiers. git filter-branch ne supprime que les références dans l'historique, mais ne supprime pas les entrées qui contiennent les données. Bien sûr, le test de cette première.

mon utilisation de disque a chuté de façon spectaculaire en faisant ceci, bien que mes conditions initiales aient été quelque peu différentes. Peut-être sous-répertoire-filtre nie ce besoin, mais j'en doute.

2
répondu 2009-06-12 08:28:42

Check out git_split project à https://github.com/vangorra/git_split

transforment les répertoires git en leurs propres dépôts 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 le transformera en un dépôt indépendant. En cours de route, il copiera tout l'historique des modifications 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.
2
répondu vangorra 2016-01-06 02:42:05

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'
1
répondu grosser 2013-03-29 20:18:09

je suis sûr que git subtree est tout bon et merveilleux, mais mes sous-répertoires de Git code géré que je voulais déplacer était tout dans eclipse. Donc si vous utilisez egit, c'est douloureusement facile. Prendre le projet que vous souhaitez déplacer et de l'équipe->débrancher, puis de l'équipe->action vers le nouvel emplacement. Il sera par défaut d'essayer d'utiliser l'ancien emplacement repo, mais vous pouvez décocher la sélection use-existing et choisir le nouvel endroit pour le déplacer. Je salue tout egit.

1
répondu stu 2016-02-10 16:57:12

je recommande de GitHub guide de fractionnement des sous-dossiers dans un nouveau dépôt . Les étapes sont similaires à la réponse de Paul , mais j'ai trouvé leurs instructions plus faciles à comprendre.

j'ai modifié les instructions pour qu'elles s'appliquent à un dépôt local, plutôt qu'à un dépôt hébergé sur GitHub.


fractionnement d'un sous-dossier en un nouveau dépôt

  1. Ouvrir Git Bash.

  2. changez le répertoire de travail courant à l'endroit où vous voulez créer votre nouveau dépôt.

  3. cloner le dépôt contenant le sous-dossier.

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
  1. modifier la répertoire de travail courant de votre dépôt cloné.

cd REPOSITORY-NAME
  1. pour filtrer le sous-dossier du reste des fichiers du dépôt, Lancez git filter-branch , en fournissant cette information:
    • FOLDER-NAME : le dossier de votre projet dans lequel vous souhaitez créer un dépôt séparé.
      • Conseil: les utilisateurs de Windows doivent utiliser / pour délimiter les dossiers.
    • BRANCH-NAME : la branche par défaut pour votre projet actuel, par exemple, master ou 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
1
répondu Steven Vascellaro 2017-08-31 14:02:49