Necesito aparecer y eliminar una confirmación "intermedia" en mi rama maestra. ¿Cómo puedo hacerlo?

94

Por ejemplo, en la siguiente rama maestra, necesito eliminar solo la confirmación af5c7bf16e6f04321f966b4231371b21475bc4da, que es la segunda debido a una rebase anterior:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <[email protected]>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <[email protected]>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Necesito mantener

  • la primera confirmación 60b413512e616997c8b929012cf9ca56bf5c9113,
  • el tercer compromiso e6523efada4d75084e81971c4dc2aec621d45530 y
  • la última confirmación 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"tirar" solo la segunda confirmación af5c7bf16e6f04321f966b4231371b21475bc4da

¿Cómo puedo hacer eso? Gracias de antemano Luca

Luca G. Soave
fuente

Respuestas:

98

Rebase o revertir son las opciones. Rebase eliminará la confirmación del historial, por lo que parecerá que la segunda confirmación nunca existió. Esto será un problema si ha enviado la rama maestra a otros repositorios. Si intenta presionar después de una rebase en este caso, git le dará un error de fusión de rechazo sin avance rápido .

Revert es la solución correcta cuando la rama se ha compartido con otros repositorios. git revert af5c7bf16hará una nueva confirmación que simplemente revierte los cambios que introdujo af5c7bf16. De esta manera, el historial no se reescribe, usted mantiene un registro claro del error y otros repositorios aceptarán el envío.

Esta es una buena manera de borrar: git rebase -i <commit>^ eso lo lleva a la confirmación justo antes de la que desea eliminar. El editor interactivo le mostrará una lista de todas las confirmaciones hasta ese momento. Puede seleccionar, aplastar, etc. En este caso, elimine la línea de la confirmación que desea borrar y guarde el archivo. Rebase terminará su trabajo.

JCotton
fuente
2
En caso de que elija Rebase, ¿cuál es el compromiso correcto para rebase? Necesito dejar solo el segundo ...
Luca G. Soave
@ BBJ3 Ver la respuesta de mipadi.
Prajwal Dhatwalia
32

Si rebase es una opción, puede rebase y simplemente soltarlo:

$ git rebase -i 414ceffc^

Si rebase no es una opción, simplemente puede revertirlo:

$ git revert af5c7bf16
mipadi
fuente
si obtuve "git rebase 414ceffc", que es la cuarta confirmación anterior, ¿no perderé también la tercera e6523 y la primera 60b41?
Luca G. Soave
3
@Luca G. Soave: Solo "pierde" una confirmación si específicamente le dice git rebaseque la elimine (ejecutando rebaseen modo interactivo y eliminando su entrada).
mipadi
Gracias mipadi, le doy mi voto a JCotton esencialmente por la explicación extensa incluso si ustedes dos dijeron lo mismo ... gracias de nuevo.
Luca G. Soave
29

A pesar de todo el crédito que recibieron las respuestas originales aquí, no las encontré para responder satisfactoriamente a la pregunta. Si se encuentra en una situación en la que necesita eliminar una confirmación o una colección de confirmaciones del medio del historial, esto es lo que sugiero:

  • Cree una nueva rama fuera del encabezado de la que contiene todas las confirmaciones y cambie a ella.
  • Revierte la nueva rama al punto desde el que deseas comenzar una nueva base.
  • Luego, (aquí está el punto clave) elija las confirmaciones posteriores que realmente desea que se apliquen después de eso desde la rama original a la nueva, y omita las confirmaciones que ya no desea (es decir, las que está eliminando).
  • Si lo desea, cambie el nombre de la rama original a algo que indique que es el código antiguo, y luego cambie el nombre de su nueva rama como se llamaba la original.
  • Finalmente, envíe sus cambios a su repositorio remoto (si usa uno). Probablemente necesitará utilizar un "empujón forzado". Si sus colaboradores tienen problemas para extraer las revisiones, podría ser más fácil para ellos simplemente clonar el repositorio nuevamente desde la fuente remota. De una forma u otra, es probable que desee hablar con ellos si de todos modos está extrayendo confirmaciones de la mitad de su historial.

Aquí hay información sobre Cherry Picking: ¿Qué significa elegir una confirmación con git?

Aquí hay algo sobre cómo hacerlo con Tortoise Git (como acabo de hacer). ¡Definitivamente es más fácil usar una utilidad de interfaz gráfica de usuario para este tipo de operaciones! Selección de cereza usando TortoiseGit

BuvinJ
fuente
6
¡Esta debería haber sido la mejor respuesta!
MadOgre
Una buena forma de usar cherry pick, esta solución es incluso mejor cuando quieres "omitir" más de una confirmación.
Johnny Willer
Realmente no aborda la pregunta original. Si bien la solución sugerida funciona, lleva mucho más tiempo / es incómoda y, en mi opinión, no aporta ningún beneficio. Si la rama ya fue empujada (y utilizada en la naturaleza), la estrategia de reversión probablemente sea la respuesta. Si no es así, lo que usaría es rebase interactivo y eliminar la confirmación ofensiva. Si fue empujado pero sabemos que nadie lo usa, aún puede salirse con la suya con un rebase seguido de un empuje forzado.
raduw