tipos tag repositorio remote origin example etiquetas eliminar crear git git-subtree

tag - git remote



Fusiona dos repositorios Git sin romper el historial de archivos (5)

Necesito fusionar dos repositorios Git en un nuevo y tercer repositorio. He encontrado muchas descripciones de cómo hacerlo utilizando una combinación de subárbol (por ejemplo, la respuesta de Jakub NarÄ™bski sobre ¿Cómo se fusionan dos repositorios Git? ) Y seguir esas instrucciones en su mayoría funciona, excepto que cuando confirmo el subárbol fusionar todos los archivos desde los repositorios antiguos se registran como nuevos archivos agregados. Puedo ver el historial de confirmaciones de los repositorios antiguos cuando hago git log , pero si hago git log <file> , solo se muestra una confirmación para ese archivo: la fusión del subárbol. A juzgar por los comentarios sobre la respuesta anterior, no estoy solo al ver este problema, pero no he encontrado soluciones publicadas para ello.

¿Hay alguna manera de fusionar repositorios y dejar intacto el historial de archivos individuales?


Convertí la solution de @Flimm en un git alias como este (agregado a mi ~/.gitconfig ):

[alias] mergeRepo = "!mergeRepo() { / [ $# -ne 3 ] && echo /"Three parameters required, <remote URI> <new branch> <new dir>/" && exit 1; / git remote add newRepo $1; / git fetch newRepo; / git branch /"$2/" newRepo/master; / git checkout /"$2/"; / mkdir -vp /"${GIT_PREFIX}$3/"; / git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} /"${GIT_PREFIX}$3/"/; / git commit -m /"Moved files to ''${GIT_PREFIX}$3''/"; / git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames /"$2/"; / git branch -D /"$2/"; git remote remove newRepo; / }; / mergeRepo"


Esta es una forma que no reescribe ningún historial, por lo que todos los ID de confirmación seguirán siendo válidos. El resultado final es que los archivos del segundo repositorio terminarán en un subdirectorio.

  1. Agregue el segundo repositorio como control remoto:

    cd firstgitrepo/ git remote add secondrepo username@servername:andsoon

  2. Asegúrate de haber descargado todas las confirmaciones de secondrepo:

    git fetch secondrepo

  3. Crea una sucursal local desde la segunda sucursal del repositorio:

    git branch branchfromsecondrepo secondrepo/master

  4. Mueva todos sus archivos a un subdirectorio:

    git checkout branchfromsecondrepo mkdir subdir/ git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} subdir/ git commit -m "Moved files to subdir/"

  5. Fusiona la segunda rama en la rama principal del primer repositorio:

    git checkout master git merge --allow-unrelated-histories branchfromsecondrepo

Su repositorio tendrá más de una confirmación raíz, pero eso no debería representar un problema.


Esta función clonará el repositorio remoto en el directorio de repos local:

function git-add-repo { repo="$1" dir="$(echo "$2" | sed ''s///$//'')" path="$(pwd)" tmp="$(mktemp -d)" remote="$(echo "$tmp" | sed ''s/////g''| sed ''s//./_/g'')" git clone "$repo" "$tmp" cd "$tmp" git filter-branch --index-filter '' git ls-files -s | sed "s,/t,&''"$dir"''/," | GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" '' HEAD cd "$path" git remote add -f "$remote" "file://$tmp/.git" git pull "$remote/master" git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master" git remote remove "$remote" rm -rf "$tmp" }

Cómo utilizar:

cd current/package git-add-repo https://github.com/example/example dir/to/save

¡Lucro!


Resulta que la respuesta es mucho más simple si simplemente intenta unir dos repositorios y hacer que parezca que fue así todo el tiempo en lugar de administrar una dependencia externa. Simplemente necesita agregar controles remotos a sus antiguos repositorios, combinarlos con su nuevo maestro, mover los archivos y carpetas a un subdirectorio, confirmar el movimiento y repetir para todos los repositorios adicionales. Los submódulos, las combinaciones de subárboles y las rebases de fantasía tienen la intención de resolver un problema ligeramente diferente y no son adecuados para lo que estaba tratando de hacer.

Aquí hay un script de Powershell de ejemplo para pegar dos repositorios juntos:

# Assume the current directory is where we want the new repository to be created # Create the new repository git init # Before we do a merge, we have to have an initial commit, so we''ll make a dummy commit dir > deleteme.txt git add . git commit -m "Initial dummy commit" # Add a remote for and fetch the old repo git remote add -f old_a <OldA repo URL> # Merge the files from old_a/master into new/master git merge old_a/master --allow-unrelated-histories # Clean up our dummy file because we don''t need it any more git rm ./deleteme.txt git commit -m "Clean up initial file" # Move the old_a repo files and folders into a subdirectory so they don''t collide with the other repo coming later mkdir old_a dir -exclude old_a | %{git mv $_.Name old_a} # Commit the move git commit -m "Move old_a files into subdir" # Do the same thing for old_b git remote add -f old_b <OldB repo URL> git merge old_b/master --allow-unrelated-histories mkdir old_b dir –exclude old_a,old_b | %{git mv $_.Name old_b} git commit -m "Move old_b files into subdir"

Obviamente, en su lugar, podría fusionar old_b en old_a (que se convierte en el nuevo repositorio combinado) si prefiere hacerlo: modifique la secuencia de comandos para adaptarla.

Si desea traer ramas de características en progreso también, use esto:

# Bring over a feature branch from one of the old repos git checkout -b feature-in-progress git merge -s recursive -Xsubtree=old_a old_a/feature-in-progress

Esa es la única parte no obvia del proceso: no es una combinación de subárbol, sino un argumento para la fusión recursiva normal que le dice a Git que hemos cambiado el nombre del objetivo y eso ayuda a Git a alinear todo correctamente.

Escribí una explicación un poco más detallada here .


por favor, eche un vistazo al uso

git rebase --root --preserve-merges --onto

para vincular dos historias al principio de sus vidas.

Si tienes caminos que se superponen, arrégleselos con

git filter-branch --index-filter

cuando usa el registro, asegúrese de "encontrar copias más difíciles" con

git log -CC

de esa manera encontrarás cualquier movimiento de archivos en la ruta.