Cómo importar repositorio Git existente en otro?
Pregunta
tengo un repositorio Git en una carpeta llamada XXX , y tengo segundo repositorio Git llama YYY .
Quiero importar el XXX repositorio en el YYY repositorio como un subdirectorio llamado ZZZ y añadir todos los XXX 's historial de cambios para YYY .
Estructura de la carpeta 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 tengo que recurrir al uso de sub-módulos?
Solución
Probablemente la forma más sencilla sería la de tirar de la XXX cosas en una rama en YYY y lo combinan con maestría:
En YYY :
git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master
git merge ZZZ --allow-unrelated-histories # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ # to get rid of the extra branch before pushing
git push # if you have a remote, that is
Yo en realidad sólo intentado esto con un par de mis repos y funciona. A diferencia respuesta de Jörg no le permitirá continúa utilizando el otro repo, pero no creo que haya especificado que de todos modos.
Nota: Puesto que esto fue escrito originalmente en 2009, GIT ha añadido la fusión subárbol mencionado en la respuesta a continuación. Probablemente me volvería a usar ese método de hoy, aunque, por supuesto, este método aún funciona.
Otros consejos
Si desea conservar la historia exacta confirmar sobre el segundo repositorio y, por tanto, también conserva la capacidad de combinar fácilmente los cambios ascendentes en el futuro, entonces aquí es el método que desee. Es el resultado de la historia no modificada del sub-árbol importado en tu repositorio más uno de combinación se comprometen a mover el repositorio fusionada al subdirectorio.
git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."
Puede seguir los cambios aguas arriba, así:
git pull -s subtree XXX_remote master
Git se da cuenta de por sí, donde las raíces son antes de hacer la fusión, por lo que no es necesario especificar el prefijo de las siguientes fusiones.
versiones Git antes 2.9 . No es necesario pasar a la opción --allow-unrelated-histories
git merge
El método de la otra respuesta que utiliza read-tree
y se salta el paso merge -s ours
es, efectivamente, no es diferente de la copia de los archivos con cp y cometer el resultado.
Fuente original era de de github "subárbol Combinar" artículo de ayuda .
git-subtree
es un guión diseñado precisamente para este caso de uso de la fusión de múltiples repositorios en uno y preservar la historia (y / o la historia de la división sub-estructuras, aunque eso es parece ser irrelevante para esta pregunta). Se distribuye como parte del árbol git desde el lanzamiento 1.7.11 .
Para combinar un <repo>
repositorio en <rev>
revisión como <prefix>
subdirectorio, utilice git subtree add
como sigue:
git subtree add -P <prefix> <repo> <rev>
git-subárbol implementa el estrategia de combinación de sub-árbol en un usuario más amigable manera.
En su caso, en el interior YYY repositorio, debe ejecutar:
git subtree add -P ZZZ /path/to/XXX.git master
No es un ejemplo bien conocido de este en el propio repositorio Git, que se conoce colectivamente en la comunidad Git como " el más frío jamás se fusionan " (después de la línea de asunto Linus Torvalds utiliza en la dirección de correo a la lista de correo Git que describe esta fusión). En este caso, el gitk
Git GUI que ahora es parte de Git adecuado, en realidad solía ser un proyecto independiente. Linus logró fusionar ese repositorio en el repositorio Git de una manera que
- aparece en el repositorio Git como si siempre hubiera sido desarrollado como parte de Git,
- toda la historia se mantiene intacto y
- que todavía puede ser desarrollada de forma independiente en su repositorio de edad, con los cambios simplemente ser
git pull
ed.
El correo electrónico contiene los pasos necesarios para reproducir, pero no es para los débiles de corazón: en primer lugar, Linus escribió Git, por lo que probablemente sabe un poco más sobre él que usted o yo , y en segundo lugar, esto fue hace casi 5 años y Git ha mejorado considerablemente desde entonces, así que tal vez ahora es mucho más fácil.
En particular, creo que hoy en día se podría usar un submódulo gitk, en ese caso específico.
La forma más sencilla de hacerlo es utilizar git formato de parche.
Supongamos que tenemos 2 repositorios Git foo y bar .
foo contiene:
- foo.txt
- .git
bar contiene:
- bar.txt
- .git
y queremos terminar arriba con foo que contiene el bar historia y estos archivos:
- foo.txt
- .git
- foobar / bar.txt
Así que para hacer eso:
1. create a temporary directory eg PATH_YOU_WANT/patch-bar
2. go in bar directory
3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
4. go in foo directory
5. git am PATH_YOU_WANT/patch-bar/*
Y si queremos volver a escribir todos los mensajes se compromete a partir de barras que podemos hacer, por ejemplo, en Linux:
git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD
Esto añadirá "[bar]" al comienzo de cada mensaje de consignación.
en este artículo , utilizando subárbol es lo que funcionó para mí y sólo se transfiere la historia aplicable. Publicar aquí por si alguien necesita los pasos (Asegúrese de reemplazar los marcadores de posición con valores aplicables a usted):
en su repositorio fuente de división subcarpeta en una nueva rama
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
en la combinación de cesión temporal de destino en la rama dividida resultado
git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result
comprobar los cambios y comprometerse
git status
git commit
No se olvide
Limpiar mediante la supresión de la rama subtree-split-result
git branch -D subtree-split-result
Eliminar el control remoto que ha añadido a buscar los datos de recompra fuente
git remote rm merge-source-repo
Esta función clonar repo repo remoto en dir locales, después de la fusión de todos los envíos, será salvo; git log
será mostrar las confirmaciones originales y caminos adecuados:
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"
}
Modo de empleo:
cd current/package
git-add-repo https://github.com/example/example dir/to/save
Si hacer unos pequeños cambios incluso se puede mover archivos / directorios de cesión temporal resultante de la fusión en diferentes caminos, por ejemplo:
repo="https://github.com/example/example"
path="$(pwd)"
tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"
git clone "$repo" "$tmp"
cd "$tmp"
GIT_ADD_STORED=""
function git-mv-store
{
from="$(echo "$1" | sed 's/\./\\./')"
to="$(echo "$2" | sed 's/\./\\./')"
GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}
# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'
git filter-branch --index-filter '
git ls-files -s |
sed "'"$GIT_ADD_STORED"'" |
GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD
GIT_ADD_STORED=""
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"
Avisos
Caminos sustituye a través de sed
, así que asegúrese de que se movió en caminos adecuados después de la fusión.
El parámetro --allow-unrelated-histories
sólo existe desde git> = 2,9.
La adición de otra respuesta ya que creo que es un poco más simple. Un tirón de repo_dest se realiza en repo_to_import y luego un empuje --set-aguas arriba url:. Repo_dest maestro se realiza
Este método ha funcionado para mí la importación de varios repositorios más pequeños en uno más grande.
Cómo importar: repo1_to_import a repo_dest
# checkout your repo1_to_import if you don't have it already
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import
# now. pull all of repo_dest
git pull url:repo_dest
ls
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master
# repeat for other repositories you want to import
Cambiar nombre o mover archivos y directorios en la posición deseada en repo original, antes de hacer la importación. p.ej.
cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import
El método descrito en el siguiente enlace inspiró esta respuesta. Me ha gustado mucho, ya que parecía más sencillo. ¡Pero cuidado! Hay dragones! https://help.github.com/articles/importing-an-external git push --mirror url:repo_dest
-git-repositorio empuja su historial repo local y estatal a distancia (url: repo_dest). PERO elimina la vieja historia y el estado del control remoto. sobreviene diversión! : -E
quería importar sólo algunos archivos de la otra repositorio (XXX) en mi caso. El subárbol era demasiado complicado para mí y las otras soluciones no funcionó. Esto es lo que hice:
ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')
Esto le da 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 tenga que añadir a la captura --follow renombra también). entonces entré en el repositorio de destino (YYY), agregó el otro depósito (XXX) como a distancia, realizó un podido recuperar de ella y finalmente:
git cherry-pick $ALL_COMMITS
que añade todas las confirmaciones a su oficina, que por lo tanto tendrá todos los archivos con su historia y puede hacer lo que quiera con ellos como si siempre han estado en este repositorio.
Yo estaba en una situación en la que estaba buscando -s theirs
pero por supuesto, no existe esta estrategia. Mi historia es que había bifurcado un proyecto en GitHub, y ahora, por alguna razón, mi master
locales no puede mezclarse con upstream/master
aunque había hecho cambios locales a esta rama. (Realmente no sé lo que pasó allí? - Supongo aguas arriba había hecho algunos empujones sucios detrás de las escenas, tal vez)
Lo que terminé haciendo fue
# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master # create new master from upstream/master
Así que ahora mi master
es nuevo en sincronía con upstream/master
(y se podría repetir lo anterior para cualquier otra rama también desea sincronizar de manera similar).
puedo sugerir otra solución (alternativa a git-submódulos ) para su problema - gil herramienta (enlaces GIT)
Se permite describir y gestionar complejas dependencias repositorios Git.
También proporciona una solución a la git recursiva submódulos dependencia problema .
Tenga en cuenta que usted tiene las siguientes dependencias del proyecto:
A continuación, se puede definir el archivo .gitlinks
con la descripción repositorios relación:
# Projects
CppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master
CppCommon CppCommon https://github.com/chronoxor/CppCommon.git master
CppLogging CppLogging https://github.com/chronoxor/CppLogging.git master
# Modules
Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git master
cpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master
fmt modules/fmt https://github.com/fmtlib/fmt.git master
HdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master
zlib modules/zlib https://github.com/madler/zlib.git master
# Scripts
build scripts/build https://github.com/chronoxor/CppBuildScripts.git master
cmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master
Cada línea describe enlace git en el siguiente formato:
- Nombre único del repositorio
- Ruta relativa del repositorio (iniciado desde el camino de .gitlinks archivo)
- repositorio Git que será utilizado en el comando git clone rama del repositorio a la caja
- línea de vacío o línea comenzaron con # no se analizan (tratados como comentario).
Por último hay que actualizar el repositorio de pruebas de raíz:
# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link
# The same result with a single command
gil update
Como el resultado podrás clonar todos los proyectos necesarios y vincularlos entre sí de una manera adecuada.
Si desea confirmar todos los cambios en algún repositorio con todos los cambios en los repositorios enlazados niño que puede hacer con un solo comando:
gil commit -a -m "Some big update"
Tire, empujar los comandos funciona de una manera similar:
gil pull
gil push
Gil (enlaces GIT) herramienta es compatible con los siguientes comandos:
usage: gil command arguments
Supported commands:
help - show this help
context - command will show the current git link context of the current directory
clone - clone all repositories that are missed in the current context
link - link all repositories that are missed in the current context
update - clone and link in a single operation
pull - pull all repositories in the current directory
push - push all repositories in the current directory
commit - commit all repositories in the current directory
Más información sobre el git recursiva submódulos problema de dependencia .
No sé de una manera fácil de hacer eso. Usted puede hacer esto:
- Uso git filter-branch para añadir un super-ZZZ directorio en el repositorio XXX
- Empuje la nueva rama en el repositorio YYY
- Combinar la rama empujó con el tronco de YYY.
puedo editar con detalles si eso suena atractivo.
Creo que se puede hacer esto utilizando 'git mv' y 'git pull'.
Soy un novato git justo - así que tenga cuidado con su repositorio principal - pero he intentado esto en un directorio temporal y parece que funciona
.En primer lugar - cambiar el nombre de la estructura de XXX para que coincida con la forma en que quiere que se vea cuando está dentro de YYY:
cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ
Ahora XXX es el siguiente:
XXX
|- ZZZ
|- ZZZ
Ahora utilice 'git pull' a buscar a los cambios a través de:
cd ../YYY
git pull ../XXX
Ahora YYY es el siguiente:
YYY
|- ZZZ
|- ZZZ
|- (other folders that already were in YYY)