tag crear git git-rebase git-subtree

crear - ¿Cómo rebase después de agregar git-subárbol?



git squash (6)

Al parecer, este es el comportamiento esperado (para una definición perversa de "comportamiento esperado"). Consulte: http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html .

No es que esto sea de mucha ayuda para nadie. Me encantaría encontrar una solución para esto también.

Estoy intentando aprender el nuevo comando git-subtree que se agregó en Git 1.7.11. Parece que pierdo la capacidad de rebase después de agregar un subárbol. Tengo el repositorio principal con el archivo README y un repositorio de biblioteca que también tiene un archivo README. Lo agrego al directorio lib con subtree add :

$ git subtree add -P lib/mylib myliborigin master

Esto funciona bien, pero ahora la historia se ve así:

* 22c1fe6 (HEAD, master) Merge commit ''b6e698d9f4985825efa06dfdd7bba8d2930cd40e'' as ''lib/mylib'' - |/ | * b6e698d Squashed ''lib/mylib/'' content from commit d7dbd3d * b99d55b Add readme * 020e372 Initial

Ahora, cuando quiero cambiar mi repositorio contra el origin/master y falla, porque el compromiso de squash se aplica directamente contra su compromiso principal, que no se aplica, porque se aplica a la raíz del repositorio y no al prefijo que le di. Al añadir el subárbol.

La razón de esto es bastante clara si miro el squash commit. No hay información sobre el prefijo. Es solo el mylib original cometido aplastado juntos. Solo el siguiente compromiso de fusión sabe algo al respecto, pero rebase no lo tiene en cuenta aquí.

¿Hay alguna solución (además de no volver a basar sobre las confirmaciones de subárbol)?


Esta es una pregunta antigua, pero tuve el mismo problema con mi repo, y finalmente encontré una solución completa, que (con suerte) conserva todos los metadatos del subárbol.

Supongamos que tenemos este árbol de compromiso:

B (master) Add README.md | A Initial commit

y bifurcamos una rama de feature con un subárbol que reside en lib/ :

git remote add -f githublib https://github.com/lib/lib.git git subtree add --prefix lib/ githublib master --squash

Crea un commit de combinación D con dos padres: nuestro master actual (B), y un commit no relacionado con el historial aplastado del repositorio externo. Esta confirmación también contiene algunos metadatos de git subtree en su mensaje de confirmación (a saber, git-subtree-dir y git-subtree-split ).

D (feature) Merged commit ''F'' as ''lib/'' / / / F Squashed ''lib/'' content from GGGGGG B (master) Add README.md | A Initial commit

Más tarde, agregamos algunos compromisos a ambas ramas de forma independiente.

E (feature) Remove .gitignore from lib/ C | (master) Add LICENSE.md | D Merged commit ''F'' as ''lib/'' | / / |/ F Squashed ''lib/'' content from GGGGGG B Add README.md | A Initial commit

Ahora queremos reajustar la feature en el master . Así es cómo:

1. Escoja las confirmaciones de la feature una por una para crear una nueva copia de la rama de la feature en la parte superior del master .

git branch -f feature C git checkout feature git cherry-pick D E E'' (feature) Remove .gitignore from lib/ | D'' Merged commit ''F'' as ''lib/'' | | E Remove .gitignore from lib/ C | (master) Add LICENSE.md | D Merged commit ''F'' as ''lib/'' | / / |/ F Squashed ''lib/'' content from GGGGGG B Add README.md | A Initial commit

Ahora tenemos el equivalente de una rebase, pero hemos perdido toda la información sobre el repositorio externo, requerido para el git subtree . Para restaurarlo:

2. Agregue el enlace principal que falta como injerto y vuelva a escribir el historial de la feature para que sea permanente.

git checkout feature git replace --graft D'' C F git filter-branch --tag-name-filter cat -- master..

Y ahora obtenemos una imagen exactamente igual a la que empezamos. Los antiguos comillas D y E todavía están por ahí, pero se pueden recolectar basura más tarde.

E'' (feature) Remove .gitignore from lib/ | D'' Merged commit ''F'' as ''lib/'' |/ | / C / (master) Add LICENSE.md | / | / | F Squashed ''lib/'' content from GGGGGG B Add README.md | A Initial commit

Advertencia: Esto vuelve a escribir el historial de feature , así que desconfíe de publicarlo si alguien más colabora con usted en esta sucursal. Sin embargo, como quería hacer un rebase en primer lugar, probablemente esté al tanto de eso :-)


Esto funciona en casos simples:

git rebase --preserve-merges master

Gracias a @Techlive Zheng en los comentarios.

Puedes ver

fatal: refusing to merge unrelated histories Error redoing merge a95986e...

Lo que significa que git no pudo aplicar automáticamente su subárbol. Esto te pone en la situación que @ericpeters describió en su respuesta. Solución:

Vuelva a agregar su subárbol (use el mismo comando que usó originalmente):

git subtree add -P lib lib-origin master

Continuar la rebase:

git rebase --continue

¡Y ya está todo listo!

Si se está preguntando si funcionó correctamente, puede comparar con su versión original después de rebasarla para asegurarse de que no haya cambiado nada:

git diff <ref-before-rebase> <ref-after-rebase> -- .

(el -- . al final le indica a git que solo diff los archivos en su directorio actual).

Si todo lo demás falla y no le importa conservar los compromisos por sí mismos, simplemente puede git cherry-pick el compromiso del subárbol original.

El mensaje de confirmación será similar al de Add ''lib/'' from commit ''9767e6...'' - ese es el que quieres.


Esto no es una solución, pero es el trabajo actual que utilizo ...

Usando su ejemplo inicial:

* 22c1fe6 (HEAD, master) Merge commit ''b6e698d9f4985825efa06dfdd7bba8d2930cd40e'' as ''lib/mylib'' - |/ | * b6e698d Squashed ''lib/mylib/'' content from commit d7dbd3d * b99d55b Add readme * 020e372 Initial

Cambie de forma interactiva a la segunda confirmación antes de agregar el subárbol:

$ git rebase -i 020e372

Elimine las dos entradas del subárbol y marque la edición para el compromiso anterior:

e b99d55b Add readme

Guarde el archivo / cerrar, luego, cuando llegue a la confirmación "Agregar Léame", ejecute el comando enmendar:

$ git commit --amend

Luego vuelva a agregar su nuevo subárbol:

$ git subtree add -P lib/mylib myliborigin master

Continuar la rebase:

$ git rebase --continue

Tu rama debe ser rediseñada fuera del maestro, y el subárbol será "normal" con Squash + la Fusión intacta:

* 22c1fe6 (HEAD, master) Merge commit ''b6e698d9f4985825efa06dfdd7bba8d2930cd40e'' as ''lib/mylib'' - |/ | * b6e698d Squashed ''lib/mylib/'' content from commit d7dbd3d


Necesitas usar

git rebase --preserve-merges --preserve-committer --onto new_place start end


Tuve un problema similar: quería volver a hacer una base después de agregar un subárbol y, al utilizar --preserve-merges, todavía quedaba un conflicto de fusión (debido a archivos .gitignore conflicto y otros).

En mi caso, no planeaba necesariamente usar ninguna funcionalidad de subárbol: simplemente estaba introduciendo un repositorio que debería haber sido parte del superproyecto originalmente. En caso de que ayude a alguien más, esto es lo que terminé haciendo, basado en otras answers related que encontré.

Supongamos que tengo dos proyectos, main_project y sub_project, en el mismo directorio. Quiero colocar sub_project en un directorio llamado sub_project dentro de main_project, suponiendo que ninguno de los dos repositorios haya tenido un directorio llamado sub_project:

cd main_project git fetch ../sub_project git checkout -b sub_project FETCH_HEAD git filter-branch --prune-empty --tree-filter '' if [[ ! -e sub_project ]]; then mkdir -p sub_project git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files sub_project fi'' git checkout branch-to-merge-within git merge sub_project git branch -d sub_project

Voy a actualizar si encuentro algún problema con este enfoque.