Tengo un repositorio de Git en una carpeta llamada XXX , y tengo un segundo repositorio de Git llamado YYY .
Quiero importar el repositorio XXX al repositorio YYY como un subdirectorio llamado ZZZ y agregar todo el historial de cambios de XXX a YYY .
Estructura de carpetas antes:
├── XXX
│ ├── .git
│ └── (project files)
└── YYY
├── .git
└── (project files)
Estructura de carpetas después de:
YYY
├── .git <-- This now contains the change history from XXX
├── ZZZ <-- This was originally XXX
│ └── (project files)
└── (project files)
¿Se puede hacer esto o debo recurrir al uso de submódulos?
Respuestas:
Probablemente, la forma más simple sería colocar las cosas XXX en una rama en AAA y luego fusionarlas en master:
En YYY :
De hecho, acabo de probar esto con un par de mis repositorios y funciona. A diferencia de la respuesta de Jörg, no le permitirá continuar usando el otro repositorio, pero no creo que haya especificado eso de todos modos.
Nota: Dado que esto se escribió originalmente en 2009, git ha agregado la combinación de subárbol mencionada en la respuesta a continuación. Probablemente usaría ese método hoy, aunque, por supuesto, este método todavía funciona.
fuente
git mv $(ls|grep -v <your foldername>) <your foldername>/
esto copiará todos los archivos y carpetas en su nueva carpetaSi desea conservar el historial de confirmación exacto del segundo repositorio y, por lo tanto, también conserva la capacidad de combinar fácilmente los cambios ascendentes en el futuro, este es el método que desea. Resulta en un historial no modificado del subárbol que se importa a su repositorio más una confirmación de fusión para mover el repositorio fusionado al subdirectorio.
Puede realizar un seguimiento de los cambios ascendentes de esta manera:
Git descubre por sí mismo dónde están las raíces antes de hacer la fusión, por lo que no necesita especificar el prefijo en las fusiones posteriores.
La desventaja es que en el historial combinado los archivos no están prefijados (no están en un subdirectorio). Como resultado,
git log ZZZ/a
le mostrará todos los cambios (si los hay) excepto aquellos en el historial combinado. Tu puedes hacer:pero eso no mostrará los cambios que no sean en el historial combinado.
En otras palabras, si no cambia
ZZZ
los archivos en el repositorioXXX
, debe especificar--follow
una ruta sin prefijar. Si los cambia en ambos repositorios, entonces tiene 2 comandos, ninguno de los cuales muestra todos los cambios.Versiones de Git anteriores a 2.9 : no es necesario pasar la
--allow-unrelated-histories
opción agit merge
.El método en la otra respuesta que usa
read-tree
y omite elmerge -s ours
paso no es diferente de copiar los archivos con cp y confirmar el resultado.La fuente original era del artículo de ayuda "Subtree Merge" de github . Y otro enlace útil .
fuente
git log
en cualquiera de los archivos que obtuve, solo veo la confirmación de fusión única y nada de su vida anterior en el otro repositorio. Git 1.8.0git log -- myfile
lugar degit log -- rack/myfile
--allow-unrelated-histories
al hacer la fusión.git-subtree
es un script diseñado exactamente para este caso de uso de fusionar múltiples repositorios en uno y preservar el historial (y / o dividir el historial de subárboles, aunque eso parece ser irrelevante para esta pregunta). Se distribuye como parte del árbol git desde la versión 1.7.11 .Para fusionar un repositorio
<repo>
en la revisión<rev>
como subdirectorio<prefix>
, usegit subtree add
lo siguiente:git-subtree implementa la estrategia de fusión de subárbol de una manera más fácil de usar.
Para su caso, dentro del repositorio AAA, debería ejecutar:
La desventaja es que en el historial combinado los archivos no están prefijados (no están en un subdirectorio). Como resultado,
git log ZZZ/a
le mostrará todos los cambios (si los hay) excepto aquellos en el historial combinado. Tu puedes hacer:pero eso no mostrará los cambios que no sean en el historial combinado.
En otras palabras, si no cambia
ZZZ
los archivos en el repositorioXXX
, debe especificar--follow
una ruta sin prefijar. Si los cambia en ambos repositorios, entonces tiene 2 comandos, ninguno de los cuales muestra todos los cambios.Más sobre esto aquí .
fuente
git subtree add -P name-of-desired-prefix ~/location/of/git/repo-without-.git branch-name
Hay una instancia bien conocida de esto en el repositorio de Git, que se conoce colectivamente en la comunidad de Git como " la fusión más genial de la historia " (después de la línea de asunto que Linus Torvalds usó en el correo electrónico a la lista de correo de Git que describe esto unir). En este caso, la
gitk
GUI de Git, que ahora es parte de Git propiamente dicha, solía ser un proyecto separado. Linus logró fusionar ese repositorio en el repositorio de Git de una manera quegit pull
editados.El correo electrónico contiene los pasos necesarios para reproducirse, pero no es para los débiles de corazón: primero, Linus escribió a Git, por lo que probablemente sepa un poco más que tú o yo, y segundo, esto fue hace casi 5 años. y Git ha mejorado considerablemente desde entonces, por lo que tal vez ahora sea mucho más fácil.
En particular, supongo que hoy en día uno usaría un submódulo gitk, en ese caso específico.
fuente
git-subtree
herramienta de terceros que puede ayudarlo con esto: github.com/apenwarr/git-subtreesubtree
estrategia de fusión, especialmente en combinación con lagit-subtree
herramienta, es una buena alternativa, quizás incluso superior a los submódulos.La forma más sencilla de hacerlo es usar git format-patch.
Supongamos que tenemos 2 repositorios git foo y bar .
foo contiene:
la barra contiene:
y queremos terminar con foo que contiene el historial de la barra y estos archivos:
Entonces para hacer eso:
Y si queremos reescribir todas las confirmaciones de mensajes desde la barra, podemos hacer, por ejemplo, en Linux:
Esto agregará "[bar]" al comienzo de cada mensaje de confirmación.
fuente
git am
es probable que falle.[ ]
del mensaje de confirmación. Por lo tanto, debe usar un marcador diferente que[bar]
Esta función clonará el repositorio remoto en el directorio de repositorio local, después de fusionar se guardarán todas las confirmaciones,
git log
se mostrarán las confirmaciones originales y las rutas adecuadas:Cómo utilizar:
Si realiza pequeños cambios, incluso puede mover archivos / directorios de repositorio fusionado a diferentes rutas, por ejemplo:
Notices
Paths reemplaza via
sed
, así que asegúrese de que se movió en las rutas adecuadas después de la fusión.El
--allow-unrelated-histories
parámetro solo existe desde git> = 2.9.fuente
gnu-sed
para que lagit-add-repo
función funcione. Gracias de nuevo Andrey!Según este artículo , usar subárbol es lo que funcionó para mí y solo se transfirió el historial aplicable. Publicar aquí en caso de que alguien necesite los pasos (asegúrese de reemplazar los marcadores de posición con valores aplicables a usted):
en su repositorio de origen dividir subcarpeta en una nueva rama
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
en su repositorio de destino fusionarse en la rama de resultados divididos
verificar sus cambios y comprometerse
No te olvides de
Limpiar eliminando la
subtree-split-result
ramagit branch -D subtree-split-result
Elimine el control remoto que agregó para obtener los datos del repositorio de origen
git remote rm merge-source-repo
fuente
Agregando otra respuesta ya que creo que esto es un poco más simple. Se realiza una extracción de repo_dest en repo_to_import y luego se ejecuta una url push --set-upstream: repo_dest master.
Este método me ha funcionado importando varios repositorios más pequeños en uno más grande.
Cómo importar: repo1_to_import to repo_dest
Cambie el nombre o mueva los archivos y directorios a la posición deseada en el repositorio original antes de realizar la importación. p.ej
El método descrito en el siguiente enlace inspiró esta respuesta. Me gustó ya que parecía más simple. ¡Pero cuidado! ¡Hay dragones! https://help.github.com/articles/importing-an-external-git-repository
git push --mirror url:repo_dest
empuja su historial y estado de repositorio local a remoto (url: repo_dest). PERO elimina la antigua historia y el estado del control remoto. La diversión se produce! :-MIfuente
En mi caso, solo quería importar algunos archivos del otro repositorio (XXX). El subárbol era demasiado complicado para mí y las otras soluciones no funcionaron. Esto es lo que hice:
Esto le proporciona una lista separada por espacios de todas las confirmaciones que afectan a los archivos que quería importar (ZZZ) en orden inverso (es posible que deba agregar también seguir para capturar los nombres). Luego entré en el repositorio de destino (AAAA), agregué el otro repositorio (XXX) como remoto, hice una búsqueda desde él y finalmente:
que agrega todos los commits a su rama, tendrá todos los archivos con su historial y podrá hacer lo que quiera con ellos como si siempre hubieran estado en este repositorio.
fuente
Vea el ejemplo básico en este artículo y considere dicha asignación en repositorios:
A
<->YYY
,B
<->XXX
Después de toda la actividad descrita en este capítulo (después de la fusión), elimine la rama
B-master
:Luego, empuje los cambios.
Esto funciona para mi.
fuente
Estaba en una situación en la que estaba buscando
-s theirs
pero, por supuesto, esta estrategia no existe. Mi historia fue que había bifurcado un proyecto en GitHub, y ahora por alguna razón, mi localmaster
no podía fusionarse,upstream/master
aunque no había realizado cambios locales en esta rama. (Realmente no sé qué pasó allí, supongo que aguas arriba había hecho algunos empujones sucios detrás de escena, ¿tal vez?)Lo que terminé haciendo fue
Entonces ahora my
master
está nuevamente sincronizado conupstream/master
(y podría repetir lo anterior para cualquier otra rama que también desee sincronizar de manera similar).fuente
git reset --hard upstream/master
en sumaster
sucursal local haría el trabajo. De esta manera, no pierde la confluencia de sucursales locales, como el flujo ascendente predeterminado.Puedo sugerir otra solución (alternativa a los submódulos git ) para su problema - herramienta gil (enlaces git)
Permite describir y administrar dependencias complejas de repositorios git.
También proporciona una solución al problema de dependencia de submódulos recursivos git .
Considere que tiene las siguientes dependencias del proyecto: ejemplo de gráfico de dependencia del repositorio git
Luego puede definir el
.gitlinks
archivo con la descripción de la relación de repositorios:Cada línea describe el enlace git en el siguiente formato:
Finalmente, debe actualizar su repositorio de muestras raíz:
Como resultado, clonará todos los proyectos necesarios y los vinculará entre sí de la manera adecuada.
Si desea confirmar todos los cambios en algún repositorio con todos los cambios en los repositorios vinculados secundarios, puede hacerlo con un solo comando:
Los comandos Pull, Push funcionan de manera similar:
La herramienta Gil (enlaces git) admite los siguientes comandos:
Más información sobre el problema de dependencia de submódulos recursivos de git .
fuente
Permítanme usar nombres
a
(en lugar deXXX
yZZZ
) yb
(en lugar deYYY
), ya que eso hace que la descripción sea un poco más fácil de leer.Digamos que quiere fusionar repositorio
a
enb
(estoy asumiendo que están situados uno junto al otro):Para esto necesita
git-filter-repo
instalar (filter-branch
se desaconseja ).Un ejemplo de fusión de 2 grandes repositorios, colocando uno de ellos en un subdirectorio: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
Más sobre esto aquí .
fuente
No sé de una manera fácil de hacer eso. PODRÍAS hacer esto:
Puedo editar con detalles si eso suena atractivo.
fuente
Creo que puedes hacer esto usando 'git mv' y 'git pull'.
Soy un git noob justo, así que tenga cuidado con su repositorio principal, pero acabo de probar esto en un directorio temporal y parece funcionar.
Primero: cambie el nombre de la estructura de XXX para que coincida con cómo desea que se vea cuando esté dentro de YYY:
Ahora XXX se ve así:
Ahora use 'git pull' para buscar los cambios en:
Ahora YYY se ve así:
fuente