2010-10-11 22 views
73

Después de convertir con éxito un repositorio SVN a Git, ahora tengo un repositorio Git muy grande que quiero descomponer en varios repositorios más pequeños y mantener el historial.Dividir el repositorio grande de Git en muchos más pequeños

Así, alguien puede ayudar con la ruptura de un acuerdo de recompra que podría tener este aspecto:

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

en dos repositorios que tener este aspecto:

MyABRepo/ 
    .git 
    DIR_A/ 
    DIR_B/ 

My12Repo/ 
    .git 
    DIR_1/ 
    DIR_2/ 

He tratado de seguir las instrucciones en este pregunta anterior, pero no encaja realmente al tratar de colocar varios directorios en un repositorio separado (Detach (move) subdirectory into separate Git repository).

+5

Cuando esté satisfecho con la respuesta, márquela como aceptada. –

+0

Para cualquiera que busque dividir directorios múltiples (anidados) en un repositorio nuevo (en lugar de buscar eliminar varios directorios, lo que podría ser más difícil en algunos proyectos), esta respuesta fue útil para mí: http://stackoverflow.com/a/19957874/164439 – thaddeusmt

Respuesta

69

Esto configurará MyABRepo; puedes hacer My12Repo de manera similar, por supuesto.

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 

Una referencia a .git/restos refs/originales/refs/heads/master. Puede eliminarlo con:

cd .. 
git clone MyABRepo.tmp MyABRepo 

Si todo fue bien, puede eliminar MyABRepo.tmp.


Si por alguna razón se produce un error con respecto .git-reescritura, puede intentar esto:

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 

Esto creará y utilizar /tmp/git-rewrite.tmp como un directorio temporal , en lugar de .git-rewrite. Naturalmente, puede sustituir cualquier ruta que desee en lugar de /tmp/git-rewrite.tmp, siempre que tenga permiso de escritura, y el directorio aún no existe.

+0

La página de manual 'git filter-branch' recomienda crear un nuevo clon del repositorio reescrito en lugar del último paso mencionado anteriormente. –

+0

@Jakub: Gracias por la corrección. – unutbu

+0

Intenté esto y obtuve un error cuando estaba intentando eliminar la carpeta .git-rewrite al final. – MikeM

8

Usted podría utilizar git filter-branch --index-filter con git rm --cached eliminar los directorios no deseados a partir de clones/copias de su repositorio originales.

Por ejemplo:

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 

Usted tendrá que eliminar manualmente las ramas que no sean necesarios de cada repositorio o etiquetas (por ejemplo, si has tenido una rama característica-x-para-AB, entonces es probable que desee eliminar esa del repositorio "12").

+0

':' no es un caracter de comentario en bash. Deberías usar '#' en su lugar. – Daenyth

+3

@Daenyth, ':' es un comando tradicional incorporado ([también especificado en POSIX] (http://www.opengroup.org/onlinepubs/009695399/utilities/colon.html)). Está incluido en * bash *, pero no es un comentario. Específicamente lo utilicé con preferencia a '#' porque no todas las shells toman '#' como un introductor de comentarios en todos los contextos (por ejemplo, interactive * zsh * sin la opción INTERACTIVE_COMMENTS habilitada). El uso de ':' hace que todo el texto sea adecuado para pegar en cualquier caparazón interactivo y también para guardarlo en un archivo de script. –

+0

¡Brillante! La única solución que encontré que mantiene todas las ramas intactas – pheelicks

0

Gracias por sus respuestas, pero terminé simplemente copiando el repositorio dos veces y borrando los archivos que no quería de cada uno. Voy a utilizar la rama de filtro en una fecha posterior para eliminar todas las confirmaciones de los archivos eliminados, ya que ya están controlados por la versión en otro lugar.

cp -R MyHugeRepo MyABRepo 
cp -R MyHugeRepo My12Repo 

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

Esto funcionó para lo que necesitaba.

EDIT: Por supuesto, lo mismo que se hizo en el My12Repo contra el A y B del directorio. Esto me dio dos repositorios con idéntica historia hasta el punto en que eliminé los directorios no deseados.

+1

Esto no conserva el historial de confirmaciones. – Daenyth

+0

¿cómo es eso? Todavía tengo todo el historial, incluso para los archivos eliminados. – MikeM

+1

Dado que su requisito no era ese repositorio A debe pretender que el repositorio B nunca existió, creo que esto (dejar registros de confirmaciones que solo afectaron a B) es una solución adecuada. Es mejor duplicar un poco de historia que modificarla. –

3

El proyecto git_split es un script simple que hace exactamente lo que está buscando.https://github.com/vangorra/git_split

Convierta los directorios de git en sus propios repositorios en su propia ubicación. Sin subárbol de negocios divertidos. Este script tomará un directorio existente en su repositorio de git y lo convertirá en un repositorio independiente propio. En el camino, se copiará durante todo el historial de cambios para el directorio que proporcionó.

./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. 
Cuestiones relacionadas