2011-01-19 11 views
9

Se habla mucho acerca de cómo no es fácil "deshacer" una fusión en git. Versión corta: si deshace un commit de fusión, también le dice a git que nunca vuelva a fusionar esos cambios en el futuro.¿Cómo puedo hacer las combinaciones de git de tal manera que sean fáciles de revertir?

¿Hay algo que pueda hacer al hacer la fusión para solucionar este problema? Hay muchas situaciones en las que deshacer una combinación sería realmente útil en el curso normal del desarrollo de software y, lo que es más importante, en el control del estado de una rama de lanzamiento, cuando los cambios deben revertirse.

edición

he visto la solución en this article y realmente no considerarlo una solución, más de una explicación del problema. Requiere

  1. utilice siempre --no-ff
  2. recordar todos sus deshechos-fusiones cuando se quiere traer de vuelta en el código que depende de ellos (esto podría ser un par de horas, días, semanas, o meses en el futuro ...)

lo que quiero

Aquí es cómo funciona en Subversion. Digamos que tengo una rama llamada "release-candidate", que es lo que ejecutamos en el servidor de transición y donde probamos las características. Digamos que me fusiono en la característica Una rama. En Subversion, es todo un conjunto de cambios, y todo el historial de todos los archivos se fusiona. Digamos que no nos gusta, así que queremos sacarlo. Simplemente deshacemos ese único conjunto de cambios y no tenemos que pensar en nada más. Podemos fusionar la rama de características A nuevamente en cualquier momento en el futuro sin tener que recordar que en un momento lo fusionamos y lo sacamos.

Me gustaría poder acercarme lo más posible a ese flujo. Me gustaría optimizar para "no tener que recordar cosas en el futuro", incluso si hace que las cosas den más pasos en el camino de alguna manera. (Esto podría ser imposible ...)

+0

¿Hay algún motivo por el que no pueda deshacer la confirmación mediante git reset --hard ORIG_HEAD? – urschrei

+0

¿Mi respuesta necesita más información? –

+0

urschrei: si lo hice en una rama en un servidor, entonces para presionar los resultados tendría que usar '--force', ¿verdad? –

Respuesta

11

ACTUALIZACIÓN:

Un flujo de trabajo que hace que sea más fácil trabajar con la rama-per-estelar está aquí: http://dymitruk.com/blog/2012/02/05/branch-per-feature/


(la parte del SVN la pregunta ha sido respondida al final)

Sí, aquí presentamos cómo reintroduce una característica que no ha cambiado. Considere la siguiente historia (se presupone que "deshecho" una fusión ya):

x---x----x--x---x--M--U--L 
    \   /
     x--x--x--x-F 

F es la rama de la característica, M es la fusión, T es la opuesta cuando unmerge esa característica, L es la última confirmación.

Éstos son sus opciones:

  1. Revert T (sin --force necesario empujar):

    x---x----x--x---x--M--U--L--^U 
        \   /
        x--x--x--x-F 
    
  2. rebase F a L (y luego fusionar --ff-only F') (sin --force necesario empujar):

    x---x----x--x---x--M--U--L 
        \   /  \ 
         x--x--x--x-x   x'--x'--x'--x'--F' 
    
  3. rebase F a L (y luego fusionar --no-ff F' - preserva su nuevo punto de ramificación) (sin --force necesaria para empujar):

    x---x----x--x---x--M--U--L-------------------M2 
        \   /  \    /
         x--x--x--x-x   x'--x'--x'--x'--F' 
    
  4. rebase -i head^^ y eliminar de la lista T (--force es necesario empujar) :

    x---x----x--x---x--M--L 
        \   /
         x--x--x--x-F 
    
  5. rebase --onto M^1 L^ L para deshacerse de la fusión y unmerge. Ahora puedes volver a poner F más tarde.

        L' 
           /
    x---x----x--x---x--M--U--L 
        \   /
         x--x--x--x-F 
    

para aplastar toda la función se compromete, utilice el modificador --squash de la fusión inicial. Dejaré que tu imaginación haga el trabajo sobre cómo se vería en la historia. Hay una razón por la que no recomiendo hacer esto. Tiene sentido saber cómo funciona una característica y qué pasos tomó. Las fusiones posteriores serán más fáciles ya que Git puede examinar el historial de por qué un determinado archivo se ve como lo hace. Aplastar los compromisos juntos pierde esa información.

Existen inconvenientes adicionales que pueden o no afectar su capacidad para aprovechar el historial de recursos.

Lo que recomiendo es marcar siempre lo que se lanza con una combinación en blanco en el máster. Esto se hace a través de una fusión con la opción --no-ff. Nunca trabajas en master y las únicas confirmaciones que se realizan son esas fusiones, sin cambios de código. En la rama QA, etiqueta la confirmación que marca el punto en el que se lanzó. Entonces, cuando haga git merge --no-ff rc-12.2, generará automáticamente un comentario de compromiso "refundido rc-12.2".

Echa un vistazo a git-flow.

Espero que le proporcione más detalles.

+1

Esa es una gran descripción general de mis opciones, pero mi pregunta era si hay algo que pueda hacer en el momento de la fusión original para simplificar las cosas en el futuro. Acabo de actualizar mi pregunta con la sección "lo que quiero". –

+1

En tu respuesta: esas son 4 opciones distintas, ¿no? ¿Quieres contarlos? Además, ¿cuál de ellos requerirá '--force' si todas las ramas se han publicado de forma remota? Sería bueno si los marca como tales .. –

+0

Lo único que me preocuparía es si no tenía trabajo en la línea principal. Esto daría como resultado una fusión de avance rápido. Esto no conserva el punto de fusión. En ese caso, cuando realice la fusión, asegúrese de especificar --no-ff para hacer una confirmación vacía con 2 padres. Esto preservará su punto de ramificación. Déjame saber si necesitas algo más. –

Cuestiones relacionadas