séparer le dépôt git par sous-dossier et conserver toutes les anciennes branches

j'ai un git repo avec 2 répertoires et plusieurs branches, je veux les diviser et créer toutes les branches

`-- Big-repo
    |-- dir1
    `-- dir2

Branches : branch1, branch2, branch3 ...

Ce que je veux

je veux diviser dir1 et dir2 comme deux pensions séparées et conserver branches branch1, branch2 ... dans les deux référentiels.

dir1
Branches : branch1, branch2, branch3 ...

dir2
Branches : branch1, branch2, branch3 ...

Ce que j'ai essayé:

je suis capable de les diviser en 2 repos en utilisant

git subtree split -P dir1 -b dir1-only 
git subtree split -P dir2 -b dir2-only 

mais, il ne crée pas de branches après la séparation.

pour obtenir toutes les branches:

git checkout branch1 (in Big-repo)
git subtree split -p dir1 -b dir1-branch1

git checkout branch2 (in Big-repo)
git subtree split -p dir1 -b dir1-branch2

And push these branches to newly created repo.

cela implique plus d'effort manuel et je suis sûr qu'il pourrait y avoir un moyen rapide pour y parvenir?

des idées???

20
demandé sur Etienne Neveu 2013-12-24 12:40:15

2 réponses

réponse Courte

git filter-branch offre exactement la fonctionnalité que vous voulez. Avec l'option --subdirectory-filter vous pouvez créer un nouvel ensemble de commits où le contenu de subDirectory est à la racine du répertoire.

git filter-branch --prune-empty --subdirectory-filter subDirectory -- --branches

Walkthrough

ce qui suit est un exemple pour effectuer cette manière sûre. Vous devez effectuer cette opération pour chaque sous-répertoire qui sera isolé dans son propre repo, dans ce cas dir1 .

premier clone de votre dépôt pour isoler les changements:

git clone yourRemote dir1Clone
cd dir1Clone

Pour préparer la cloné référentiel, nous allons recréer toutes les branches locales. Nous sautons celui qui commence par * puisque c'est la branche courante, qui dans ce cas se lirait (no branch) puisque nous sommes dans un état sans tête:

# move to a headless state
# in order to delete all branches without issues
git checkout --detach

# delete all branches
git branch | grep --invert-match "*" | xargs git branch -D

pour recréer toutes les branches éloignées localement on passe en revue les résultats de git branch --remotes . Nous sautons ceux qui contiennent -> car ce ne sont pas des branches:

# get all local branches for remote
git branch --remotes --no-color | grep --invert-match "\->" | while read remote; do
    git checkout --track "$remote"
done

# remove remote and remote branches
git remote remove origin

exécute finalement la commande filter-branch . Cela créera de nouvelles propagations avec toutes les propagations qui touchent le sous-répertoire dir1 . Toutes les branches qui touchent aussi ce sous-répertoire seront mises à jour. La sortie listera toutes les références qui n'ont pas été mises à jour, ce qui est le cas pour les branches qui ne touchent pas du tout dir1 .

# Isolate dir1 and recreate branches
# --prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --prune-empty --subdirectory-filter dir1 -- --all

Après cela, vous aurez une nouvelle série de commits qui ont dir1 à la racine du dépôt. Il suffit d'ajouter votre télécommande pour pousser les nouvelles propagations, ou de les utiliser comme un nouveau dépôt.

comme dernière étape supplémentaire si vous vous souciez de la taille du dépôt:

même si toutes les branches où votre dépôt a été mis à jour auront toujours tous les objets du dépôt original, ils ne seront accessibles qu'à travers la ref-journaux. Si vous voulez laisser tomber ceux-ci Lire comment collecter les ordures commits

Quelques ressources supplémentaires:

36
répondu LopSae 2017-05-23 12:17:06

ce script fait le travail pour moi:

#!/bin/bash

set -e

if [ -z "" ]; then
        echo "usage: "151900920" /full/path/to/repository path/to/splitfolder/from/repository/root new_origin"
        exit
fi

repoDir=
folder=
newOrigin=

cd $repoDir

git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D

for remote in `git branch --remotes | grep --invert-match "\->"`
do
        git checkout --track $remote
        git add -vA *
        git commit -vam "Changes from $remote" || true
done

git remote remove origin
git filter-branch --prune-empty --subdirectory-filter $folder -- --all

#prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune

#upload to new remote
git remote add origin $newOrigin
git push origin master

for branch in `git branch | grep -v '\*'`
do
        git push origin $branch
done
5
répondu Arohi 2018-06-18 20:45:44