Rama de Git rebase con todas las ramas principales (o ramas secundarias dependientes)

5 minutos de lectura

avatar de usuario de knittl
tejer

¿Es posible reorganizar una rama con todas sus ramas principales con Git? (Creo que “ramas principales” es la forma correcta para usar aquí. Dependiendo de su punto de vista, también puede llamarlas subramas dependientes. Sin embargo, seguir los punteros principales de las confirmaciones lo llevará a esas ramas, así que en mi humilde opinión es justo llamarlas “ramas matrices”).

A menudo uso ramas como etiquetas/puntos de control rápidos/mutables para marcar ciertas confirmaciones. Todas las sucursales principales/referencias principales se incluyen por completo en la rama que se va a reorganizar; no hay confirmaciones solo en las ramas principales.

* master
*
* featureA-finished
*
* origin/master

ahora quiero rebase -i master sobre origin/master para cambiar/reformular la confirmación featureA-finished^

Después git rebase -i --onto origin/master origin/master masterbásicamente quiero que la historia sea:

* master
*
* featureA-finished
* (changed/reworded)
* origin/master

pero lo que obtengo es:

* master
*
* (same changeset as featureA-finished)
* (changed/reworded)
| * featureA-finished
|.* (original commit i wanted to edit)
* origin/master

¿Hay alguna forma de evitarlo, o estoy atascado con la recreación de todas las ramas principales, más específicamente las etiquetas de las ramas, en las confirmaciones nuevas y reorganizadas?

Esta pregunta está relacionada, pero aún es muy diferente, a Rebasar una rama que incluye a todos sus hijos.

  • Podrías usar en lugar de ramas git notes para marcar sus confirmaciones: creo que se copian automáticamente durante las rebases. (Es una característica nueva, por lo que necesitará la última versión) kernel.org/pub/software/scm/git/docs/git-notes.html

    – Cascabel

    17 de junio de 2010 a las 13:50

  • Vea también cómo cambiaría la base de un subhistorial completo: varias ramas, con algunos enlaces entre ellas como resultado de la fusión. La parte desagradable de esa solución es la necesidad de restablecer las referencias de la rama del tema a las nuevas confirmaciones reorganizadas después.

    – imz — Iván Zakharyaschev

    14/03/2012 a las 22:07

Avatar de usuario de RobM
RobM

Según git modelo de objeto si solo cambia los metadatos de una confirmación (es decir, un mensaje de confirmación) pero no los datos subyacentes (“árbol(es)”) contenidos en él, su hash de árbol permanecerá sin cambios.

Además de editar un mensaje de confirmación, también está realizando una reorganización, que cambiará los valores hash del árbol de cada confirmación en su historial, porque cualquier cambio extraído de origin/master afectará los archivos en su historial reescrito: lo que significa que algunos de los archivos (blobs) que sus puntos de confirmación han cambiado.

Así que no hay una forma a prueba de balas de hacer lo que quieres.

Dicho esto, editar un compromiso con rebase -i por lo general, no altera la marca de tiempo y el autor de la confirmación, por lo que podría usar esto para identificar de manera única sus confirmaciones antes y después de una operación de reorganización.

Tendría que escribir un script que registre todos los puntos de inicio de la rama contra estos identificadores de “marca de tiempo: autor” antes de hacer una reorganización, y luego encontrar las confirmaciones reescritas con el mismo ID de “marca de tiempo: autor” y reorganizar la rama en él.

Lamentablemente, no tengo tiempo para intentar escribir este guión yo mismo ahora, ¡así que solo puedo desearte la mejor de las suertes!

Editar: Puede obtener la dirección de correo electrónico y la marca de tiempo del autor mediante:

$ git log --graph --all --pretty=format:"%h %ae:%ci"
* 53ca31a robert.meerman@gmail.com:2010-06-16 13:50:12 +0100
* 03dda75 robert.meerman@gmail.com:2010-06-16 13:50:11 +0100
| * a8bb03a robert.meerman@gmail.com:2010-06-16 13:49:46 +0100
| * b93e59d robert.meerman@gmail.com:2010-06-16 13:49:44 +0100
|/
* d4214a2 robert.meerman@gmail.com:2010-06-16 13:49:41 +0100

Y puede obtener una lista de sucursales para cada uno de estos en función de su hash de confirmación:

$ git branch --contains 03dda75
* testbranch

Tenga cuidado con las ramas múltiples por confirmación, el ancestro común d4214a2 pertenece a ambas ramas!

avatar de usuario de knittl
tejer

Parece que esta característica está entrando lentamente en Git. rebase ganará la opción --rebase-refs que hará exactamente lo que pidió mi respuesta original. Para la serie de parches propuesta ver el hilo rebase: comando “ref” y opciones –rewrite-{refs,heads,tags} en gmane.


Actualización 2022:

La opción --update-refs finalmente aterrizó en Git v2.38.0, que ahora puede hacer exactamente lo que se le preguntó en la pregunta inicial hace más de 12 años 🙂

Esta función se fusionó con commit 3d8e3dc4fc22fe41f8ee1184f085c600f35ec76f en agosto. ¡Hurra!

  • Es una lástima que esto parece no haber entrado en Git: ¡No he visto tal característica en la documentación actual (página de manual) para git-rebase! (git-1.7.9.3)

    – imz — Iván Zakharyaschev

    14/03/2012 a las 22:10

No estoy seguro de cómo llegaste allí exactamente, pero:

git branch -f (same changeset as featureA-finished)

debería ser suficiente para restablecer su featureA-finished sucursal con la historia correcta.

  • sí, eso es lo que quise decir con “recrear las ramas en las nuevas confirmaciones reorganizadas”. Sé que es posible de esta manera, pero ya se vuelve muy engorroso para tres sucursales.

    – tejer

    28 de abril de 2010 a las 18:19

  • @knittl: interesante. Un diagrama de registro más detallado de esas ramas antes y después podría ayudar aquí.

    – VoC

    28 de abril de 2010 a las 18:46

  • solo imagine el mismo gráfico con 15 compromisos, cada segundo compromiso está terminado con la característica A, terminado con la característica B, terminado con la característica C, etc.

    – tejer

    28 de abril de 2010 a las 19:11

Avatar de usuario de Walter Mundt
walter mundt

Lo que te aconsejo es rebase featureA-finished sobre origin/master primero. Haga el paso de reformulación entonces. Después de eso, rebase master sobre featureA-finished. Esto le dará el resultado final que desea.

Tenga en cuenta que tendrá que usar -i en ambos rebases, y es posible que deba eliminar todas las confirmaciones del original featureA-finshed abajo en el segundo rebase. Si quisiera, podría escribir un script que eliminaría esto guardando la rama intermedia y usándola como base para una reorganización. --onto la nueva versión Incluso podría manejar una secuencia de tales ‘subramas’ si lo escribiera correctamente. Si necesitas ayuda, puedo intentar sacar uno.

¿Ha sido útil esta solución?