web-dev-qa-db-fra.com

Divisez le grand référentiel Git en plusieurs plus petits

Après avoir réussi à convertir un référentiel SVN en Git, j'ai maintenant un très grand référentiel Git que je souhaite décomposer en plusieurs référentiels plus petits et conserver l'historique.

Alors, quelqu'un peut-il aider à rompre un dépôt qui pourrait ressembler à ceci:

MyHugeRepo/
   .git/
   DIR_A/
   DIR_B/
   DIR_1/
   DIR_2/

Dans deux référentiels qui ressemblent à ceci:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/

J'ai essayé de suivre les instructions de cette question précédente, mais cela ne convient pas vraiment lorsque vous essayez de placer plusieurs répertoires dans un référentiel séparé ( Détacher (déplacer) le sous-répertoire dans un référentiel Git séparé ).

84
MikeM

Cela va configurer MyABRepo; vous pouvez faire My12Repo de la même manière bien sûr.

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch --Prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 

Une référence à .git/refs/original/refs/heads/master reste. Vous pouvez supprimer cela avec:

cd ..
git clone MyABRepo.tmp MyABRepo

Si tout s'est bien passé, vous pouvez supprimer MyABRepo.tmp.


Si, pour une raison quelconque, vous obtenez une erreur concernant .git-rewrite, vous pouvez essayer ceci:

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch -d /tmp/git-rewrite.tmp --Prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 
cd ..
git clone MyABRepo.tmp MyABRepo

Cela créera et utilisera /tmp/git-rewrite.tmp comme répertoire temporaire, au lieu de .git-rewrite. Naturellement, vous pouvez remplacer le chemin de votre choix au lieu de /tmp/git-rewrite.tmp, tant que vous disposez d'une autorisation d'écriture et que le répertoire n'existe pas déjà.

78
unutbu

Vous pouvez utiliser git filter-branch --index-filter avec git rm --cached pour supprimer les répertoires indésirables des clones/copies de votre référentiel d'origine.

Par exemple:

trim_repo() { : trim_repo src dst dir-to-trim-out...
  : uses printf %q: needs bash, zsh, or maybe ksh
  git clone "$1" "$2" &&
  (
    cd "$2" &&
    shift 2 &&

    : mirror original branches &&
    git checkout HEAD~0 2>/dev/null &&
    d=$(printf ' %q' "$@") &&
    git for-each-ref --Shell --format='
      o=%(refname:short) b=${o#Origin/} &&
      if test -n "$b" && test "$b" != HEAD; then 
        git branch --force --no-track "$b" "$o"
      fi
    ' refs/remotes/Origin/ | sh -e &&
    git checkout - &&
    git remote rm Origin &&

    : do the filtering &&
    git filter-branch \
      --index-filter 'git rm --ignore-unmatch --cached -r -- '"$d" \
      --tag-name-filter cat \
      --Prune-empty \
      -- --all
  )
}
trim_repo MyHugeRepo MyABRepo DIR_1 DIR_2
trim_repo MyHugeRepo My12Repo DIR_A DIR_B

Vous devrez supprimer manuellement les branches ou balises inutiles de chaque référentiel (par exemple, si vous aviez une branche feature-x-for-AB, vous souhaiterez probablement la supprimer du référentiel "12").

10
Chris Johnsen

Le projet git_split est un script simple qui fait exactement ce que vous recherchez. https://github.com/vangorra/git_split

Transformez les répertoires git en leurs propres référentiels dans leur propre emplacement. Aucune entreprise drôle de sous-arbre. Ce script prendra 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 tout l'historique des modifications du 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.
5
vangorra

Voici un script Ruby qui le fera. https://Gist.github.com/43410

4
EnabrenTane

Merci pour vos réponses mais j'ai fini par copier le référentiel deux fois puis supprimer les fichiers que je ne voulais pas de chacun. Je vais utiliser la branche de filtre à une date ultérieure pour supprimer tous les commits pour les fichiers supprimés car ils sont déjà contrôlés en version ailleurs.

cp -R MyHugeRepo MyABRepo
cp -R MyHugeRepo My12Repo

cd MyABRepo/
rm -Rf DIR_1/ DIR_2/
git add -A
git commit -a

Cela a fonctionné pour ce dont j'avais besoin.

EDIT: Bien sûr, la même chose a été faite dans le My12Repo contre le répertoire A et B. Cela m'a donné deux dépôts avec un historique identique jusqu'au moment où j'ai supprimé les répertoires indésirables.

1
MikeM