2010-10-11 11 views
73

Dopo aver convertito correttamente un repository SVN in Git, ora ho un repository Git molto grande che voglio suddividere in più repository più piccoli e mantenere la cronologia.Diviso il repository Git di grandi dimensioni in molti più piccoli

Così, qualcuno può aiutare con rottura di un pronti contro termine che potrebbe essere simile a questo:

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

in due repository che assomigliano a questo:

MyABRepo/ 
    .git 
    DIR_A/ 
    DIR_B/ 

My12Repo/ 
    .git 
    DIR_1/ 
    DIR_2/ 

Ho provato seguendo le indicazioni in questo domanda precedente ma non si adatta perfettamente quando si tenta di inserire più directory in un repository separato (Detach (move) subdirectory into separate Git repository).

+5

Quando si è soddisfatti di una risposta, contrassegnarla come accettata. –

+0

Per chi cerca di suddividere più directory (nidificate) in un nuovo repository (invece di cercare di rimuovere più directory, che potrebbe essere più difficile su alcuni progetti), questa risposta è stata utile per me: http://stackoverflow.com/a/19957874/164439 – thaddeusmt

risposta

69

Ciò configurerà MyABRepo; puoi fare My12Repo allo stesso modo, ovviamente.

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 

Un riferimento a .git/refs/original/refs/heads/master rimane. È possibile rimuovere quello in su con:

cd .. 
git clone MyABRepo.tmp MyABRepo 

Se tutto è andato bene si può rimuovere MyABRepo.tmp.


Se per qualche motivo si ottiene un errore su .git-rewrite, si può provare questo:

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 

Questo creerà e utilizzare /tmp/git-rewrite.tmp come una directory temporanea , invece di .git-rewrite. Naturalmente, è possibile sostituire qualsiasi percorso che si desidera invece di /tmp/git-rewrite.tmp, a condizione che si disponga dell'autorizzazione alla scrittura e che la directory non esista già.

+0

La manpage "git filter-branch" consiglia di creare un nuovo clone di repository riscritto anziché l'ultimo passaggio sopra menzionato. –

+0

@Jakub: Grazie per la correzione. – unutbu

+0

Ho provato questo e ho ricevuto un errore quando stava cercando di eliminare la cartella .git-rewrite alla fine. – MikeM

8

È possibile utilizzare git filter-branch --index-filter con git rm --cached per eliminare le directory indesiderate dai cloni/copie del repository originale.

Ad esempio:

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' "[email protected]") && 
    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 

Sarà necessario eliminare manualmente i rami non necessari di ogni repository o tag (ad esempio, se si ha un ramo caratteristica-x-per-AB, allora probabilmente si desidera eliminare che dal repository "12").

+0

':' non è un carattere di commento in bash. Dovresti invece usare '#'. – Daenyth

+3

@Daenyth, ':' è un comando incorporato tradizionale ([specificato anche in POSIX] (http://www.opengroup.org/onlinepubs/009695399/utilities/colon.html)). È incluso in * bash *, ma non è un commento. L'ho usato in modo specifico preferenzialmente su # # perché non tutte le shell prendono '#' come un introduttore di commenti in tutti i contesti (ad esempio interattivo * zsh * senza l'opzione INTERACTIVE_COMMENTS abilitata). Usando ':' rende l'intero testo adatto per incollare in qualsiasi shell interattiva e salva in un file di script. –

+0

Brillante! Ho trovato solo la soluzione che mantiene intatti tutti i rami – pheelicks

0

Grazie per le vostre risposte, ma alla fine ho solo copiato il repository due volte e poi cancellato i file che non volevo da entrambi. Utilizzerò il filtro-ramo in un secondo momento per eliminare tutti i commit dei file cancellati poiché sono già controllati in altre versioni.

cp -R MyHugeRepo MyABRepo 
cp -R MyHugeRepo My12Repo 

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

Questo ha funzionato per quello che mi serviva.

MODIFICA: Ovviamente, la stessa cosa è stata eseguita in My12Repo rispetto alla directory A e B. Questo mi ha dato due repository con una storia identica fino al punto in cui ho cancellato le directory indesiderate.

+1

Questo non conserva la cronologia dei commit. – Daenyth

+0

in che modo? Ho ancora tutta la cronologia, anche per i file cancellati. – MikeM

+1

Dato che il tuo requisito non era quello repo A deve fingere che il repo B non sia mai esistito, penso che questo (lasciando una registrazione di commit che riguardasse solo B) sia una soluzione appropriata. Meglio duplicare un po 'di storia che distruggerlo. –

3

Il progetto git_split è un semplice script che fa esattamente quello che stai cercando.https://github.com/vangorra/git_split

Trasforma le directory git nei propri repository all'interno della propria posizione. Nessun business divertente sotteso. Questo script prenderà una directory esistente nel tuo repository git e trasformerà quella directory in un suo repository indipendente. Lungo la strada, copierà l'intera cronologia delle modifiche per la directory che hai fornito.

./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. 
Problemi correlati