¿Los commands de Git para subtree automáticamente fusionar un proyecto con submodules?

Encontré Using Git, ¿cuál es la mejor manera de subtree fusionar un proyecto externo que tiene submodules? pero mientras está relacionado, no responde mi pregunta.

Supongamos que tengo mi proyecto Parent y mi proyecto Child, que contiene submodules. ¿Cómo puedo subtree fusionar el proyecto Child en un subdirectory del proyecto Parent y mantener las references a los submodules funcionando?

He intentado cosas como:

git remote add -f child_remote git://github.com/me/child.git git checkout -b child_branch child_remote/master git submodule init git submodule update git checkout master git read-tree --prefix=child_directory/ -u child_branch 

Pero read-tree pierde los submodules, y .gitmodules aparece solo en el subdirectory. Cuando trato de hacer git submodule init y git submodule update, obtengo errores como "No se encontraron maps de submodules en .gitmodules para la ruta 'child_directory / submodule_directory'".

También intenté modificar las instrucciones en http://help.github.com/subtree-merge/ para trabajar con submodules, pero fue en vano.

Entiendo que puedo lograr esto modificando manualmente el file .gitmodules para referirme a la ruta correcta, o fusionarme en el proyecto Child sin submodules y luego volver a agregarlos al proyecto principal, pero considero que ambas soluciones son hacks . Estoy buscando los commands reales que se ejecutarían para que esto funcione automáticamente, sin tener que editar nada manualmente.

Podrías cambiar las routes en .gitmodules y luego hacer git submodule init && git submodule update o podrías convertir los submodules en subtreees. La última opción implica algún tipo de script porque no hay una forma automática de hacerlo.

Al usar un script de shell puede usar estas funciones para get los submodules y sus nombres (de la fuente git-submodules):

 # This lists the unmerged submodules module_list() { git ls-files --error-unmatch --stage -- "$@" | perl -e ' my %unmerged = (); my ($null_sha1) = ("0" x 40); while (<STDIN>) { chomp; my ($mode, $sha1, $stage, $path) = /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/; next unless $mode eq "160000"; if ($stage ne "0") { if (!$unmerged{$path}++) { print "$mode $null_sha1 U\t$path\n"; } next; } print "$_\n"; } ' } # This gets the submodule's name from the .gitignore file in your webroot module_name() { # Do we have "submodule.<something>.path = $1" defined in .gitmodules file? re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g') name=$( git config -f $2/.gitmodules --get-regexp '^submodule\..*\.path$' | sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' ) test -z "$name" && die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")" echo "$name" } 

Luego, cuando itere los resultados, puede extraer el nombre y la url para usar para los subtreees.

 module_list | while read mode sha1 stage path do #the path as your repo sees it full_path=$path #The path as .gitmodules in your child_directory sees it fake_path=${path[*]/[child_directory]\//} #Get the name of the submodule stupid_name=$(module_name "$fake_path" "[child_directory]") #Get the git URL from the .gitmodules file git_url=$(git config -f [child_directory]/.gitmodules submodule."$stupid_name".url) #Gets the clean name to use as remote name new_remote=$(echo $git_url | cut -d. -f2 | cut -d/ -f2- | cut -d/ -f2) #Remove the submodules folder rm -rf $path #Add the subtree git remote add -f $new_remote $git_url git merge -s ours --no-commit $new_remote/master git read-tree --prefix=$full_path/ -u $new_remote/master git commit -m "$new_remote merged in $full_path" done 

Estoy seguro de que hay una manera mucho mejor de hacerlo, pero da una idea de lo que se debe hacer

¿Por qué no usar submodules en su proyecto? Ahora puede usar 'git submodule update –recursive` en general.

También existe git-slave para ayudarlo a automatizar las sucursales en los submodules.