tag - Merge el repositorio de git en el subdirectorio
que es un repositorio git (5)
¿Has intentado agregar el repositorio adicional como un submódulo git? No fusionará la historia con el repositorio contenedor, de hecho, será un repositorio independiente.
Lo menciono, porque no lo has hecho.
Me gustaría fusionar un repositorio de git remoto en mi repositorio de git en funcionamiento como subdirectorio de él. Me gustaría que el repositorio resultante contenga el historial fusionado de los dos repositorios y también que cada archivo del repositorio fusionado conserve su historial tal como estaba en el repositorio remoto. Traté de usar la estrategia de subárbol como se menciona en Cómo usar la estrategia de combinación de subárbol , pero después de seguir ese procedimiento, aunque el repositorio resultante contiene efectivamente el historial fusionado de los dos repositorios, los archivos individuales provenientes del remoto no conservaron su historial (`git log ''en cualquiera de ellos solo muestra un mensaje" Fusionado combinado ... ").
Además, no quiero usar submódulos porque no quiero que los dos repositorios de git combinados estén separados.
¿Es posible fusionar un repositorio de git remoto en otro como un subdirectorio con archivos individuales procedentes del repositorio remoto que conserva su historial?
Muchas gracias por la ayuda.
EDITAR: Actualmente estoy probando una solución que usa git filter-branch para reescribir el historial del repositorio fusionado. Parece que funciona, pero necesito probarlo un poco más. Volveré para informar sobre mis hallazgos.
EDIT 2: En la esperanza de ser más claro, doy los comandos exactos que utilicé con la estrategia de subárbol de git, que da como resultado una aparente pérdida de historial de los archivos del repositorio remoto. Deje A ser el git repo en el que estoy trabajando actualmente y B el git repo que me gustaría incorporar a A como subdirectorio de él. Hizo lo siguiente:
git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."
Después de estos comandos y yendo al directorio subdir / Iwant / to / put / B / in, veo todos los archivos de B, pero git log
on cualquiera de ellos muestra solo el mensaje de confirmación "Merge B como subdirectorio en subdir / Iwant / to / put / B / in " Su historial de archivos como está en B se pierde.
Lo que parece funcionar (dado que soy un principiante en git, puedo estar equivocado) es el siguiente:
git remote add -f B <url-of-B>
git checkout -b B_branch B/master # make a local branch following B''s master
git filter-branch --index-filter /
''git ls-files -s | sed "s-/t/"*-&subdir/Iwant/to/put/B/in/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new /
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'' HEAD
git checkout master
git merge B_branch
El comando anterior para filter-branch está tomado de git help filter-branch
, en el que solo cambié la ruta del subdirectorio.
Después de obtener la explicación más completa de lo que está sucediendo, creo que lo entiendo y, en cualquier caso, en la parte inferior tengo una solución alternativa. Específicamente, creo que lo que está sucediendo es que la detección de cambio de nombre está siendo engañada por el subárbol se funden con --prefix. Aquí está mi caso de prueba:
mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
git commit -a -m BB
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
git read-tree --prefix=bdir -u B/master
git commit -m "subtree merge B into bdir"
cd bdir
echo BBB>>B
git commit -a -m BBB
Hacemos los directorios de git ayb con varios commits cada uno. Hacemos una fusión de subárbol, y luego hacemos una confirmación final en el nuevo subárbol.
Al ejecutar gitk
(en z / a) se muestra que el historial aparece, podemos verlo. La ejecución de git log
muestra que el historial aparece. Sin embargo, mirar un archivo específico tiene un problema: git log bdir/B
Bueno, hay un truco que podemos jugar. Podemos ver el historial previo al cambio de nombre de un archivo específico usando --follow. git log --follow -- B
Esto es bueno, pero no es excelente, ya que no puede vincular el historial de la fusión previa con la fusión posterior.
Intenté jugar con -M y -C, pero no pude lograr que siguiera un archivo específico.
Entonces, la solución, creo, es decirle a git sobre el cambio de nombre que se llevará a cabo como parte de la fusión del subárbol. Desafortunadamente git-read-tree es bastante quisquilloso con las combinaciones de subárboles, así que tenemos que trabajar a través de un directorio temporal, pero eso puede desaparecer antes de comprometernos. Luego, podemos ver la historia completa.
Primero, crea un repositorio "A" y realiza algunos commits:
mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
Segundo, crea un repositorio "B" y realiza algunos commits:
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
Y el truco para hacer que esto funcione : obligue a Git a reconocer el cambio de nombre creando un subdirectorio y moviendo los contenidos dentro de él.
mkdir bdir
git mv B bdir
git commit -a -m bdir-rename
Regrese al repositorio "A" y busque y combine el contenido de "B":
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
git read-tree --prefix= -u B/master
git commit -m "subtree merge B into bdir"
Para mostrar que ahora están fusionados:
cd bdir
echo BBB>>B
git commit -a -m BBB
Para demostrar que la historia completa se conserva en una cadena conectada:
git log --follow B
Obtenemos la historia después de hacer esto, pero el problema es que si realmente mantiene el viejo repositorio "b" y ocasionalmente se fusiona (digamos que en realidad es un repositorio mantenido por terceros) usted está en problemas ya que ese tercero no habrá hecho el cambio de nombre. Debes tratar de combinar nuevos cambios en tu versión de b con el cambio de nombre y me temo que eso no irá bien. Pero si b se va, tú ganas.
Encontré la siguiente solución viable para mí. Primero voy al proyecto B, creo una nueva rama en la que ya todos los archivos se moverán al nuevo subdirectorio. Luego empujo esta nueva rama al origen. A continuación, voy al proyecto A, agrego y obtengo el control remoto de B, luego pago la transferencia de la rama movida, regreso al maestro y me fusiono:
# in local copy of project B
git checkout -b prepare_move
mkdir subdir
git mv <files_to_move> subdir/
git commit -m ''move files to subdir''
git push origin prepare_move
# in local copy of project A
git remote add -f B_origin <remote-url>
git checkout -b from_B B_origin/prepare_move
git checkout master
git merge from_B
Si voy al subdirectorio subdirectorio, puedo usar git log --follow
y todavía tengo el historial.
No soy un experto en git, así que no puedo comentar si esta es una solución particularmente buena o si tiene algunas advertencias, pero hasta ahora todo parece ir bien.
Si realmente quieres unir cosas, busca injertos. También deberías estar usando git rebase --preserve-merges --onto
. También hay una opción para mantener la fecha del autor para la información del committer.
git-subtree
es un script diseñado exactamente para este caso de uso de fusión de múltiples repositorios en uno preservando el historial (y / o dividiendo 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 combinar un repositorio <repo>
en la revisión <rev>
como subdirectorio <prefix>
, use git subtree add
siguiente manera:
git subtree add -P <prefix> <repo> <rev>
git-subárbol implementa la estrategia de fusión de subárbol de una manera más fácil de usar.