Agregar cambios a un commit anterior con Magit

44

Tengo 2 commits, A y B, listos para ser empujados. Me doy cuenta de que olvidé agregar algo en A.

¿Cómo puedo agregar este cambio a A usando Magit? Ni siquiera sé qué parte de la documentación de Git debería mirar.

Mathieu Marques
fuente

Respuestas:

69

Supongamos por un momento que desea agregar algo a la HEADconfirmación, es decir, "la segunda confirmación B" en su ejemplo.

La ventana emergente de confirmación cpresenta un enlace " aEnmendar". Al presionar esa tecla "enmendará" los cambios organizados en la HEADconfirmación. Como las confirmaciones no son mutables en Git, esto reemplazará la confirmación anterior por una nueva confirmación. Aparecerá un búfer con el mensaje de confirmación anterior, para que pueda modificarlo en caso de que el cambio agregado también requiera que ajuste el mensaje. Como siempre, presione C-c C-ccuando haya terminado de editar el mensaje. Esto es equivalente a correr git commit --amenden la línea de comando.

  • a Modificar : agregue los cambios organizados HEADy edite su mensaje de confirmación

Como a menudo sucede que solo tiene que ajustar el cambio o el mensaje, Magit ofrece dos variantes adicionales:

  • e Extender : agregue los cambios por etapas HEADsin editar el mensaje de confirmación
  • w Reformular : cambie el mensaje de HEADsin agregarle los cambios por etapas

Cuando desee editar una confirmación que no lo es HEAD, entonces lo anterior no funcionará. Estos comandos siempre "modifican" (es decir, reemplazan) el HEADcommit. Git no proporciona un solo comando para modificar una confirmación que no sea, HEADpor lo que esto es un poco más complicado.

Magit qué proporciona un comando tal, sino porque hay situaciones en las que es preferible hacer esto en varios pasos, vamos a hablar de eso en primer lugar.

La modificación de una confirmación que no HEADse puede dividir en tres pasos:

  1. Temporalmente haga que el otro commit ( A) el HEAD.
  2. Modifique el HEAD(como se describe anteriormente), lo que resulta en confirmación A'.
  3. Dile a Git que vuelva a aplicar los commits que siguieron A, pero además A'.

Esto se puede hacer usando un rebase interactivo. Escriba rpara mostrar la ventana emergente de rebase. Luego escriba mpara invocar la variante de rebase "editar un compromiso". Aparece un búfer con confirmaciones recientes. Vaya a la confirmación que desea modificar y escriba C-c C-cpara seleccionarla. Git luego rebobina el historial a esa confirmación y muestra información sobre el cambio continuo en el búfer de estado.

Modifique HEADcomo se describe arriba. Luego dile a Git que has terminado escribiendo r r. If A'y Bconflict, rebase se detendrá By tendrá que resolver el conflicto. Después de hacerlo, presione r rpara continuar.

Si sabe que sus cambios Adarán lugar a conflictos con B, proceda como se describe anteriormente; de ​​lo contrario, utilice el siguiente enfoque.


Git permite crear "confirmaciones de reparación" usando git commit --fixup A. Esto crea una nueva confirmación, que registra los cambios que "deberían haberse realizado en otra confirmación". Ese compromiso se convierte en lo nuevo HEAD. También existe una --squashvariante. Para obtener información sobre las diferencias, consulte la git-commitpágina del manual.

Para combinar realmente el Acommit y el nuevo commit A'y luego volver Ba aplicar, debes usar rebase. Magit proporciona un comando conveniente para hacerlo r f.

La principal diferencia con el enfoque anterior es que aquí primero creamos una nueva confirmación y luego la reformulamos para combinarla con el "objetivo" y volver a aplicar B. Arriba comenzamos con rebase en lugar de comprometernos.

En Magit, tanto la --fixupy las --squashvariantes están disponibles en la ventana emergente de confirmación, en fy s. Pero Magit también proporciona variantes "instantáneas" de los comandos de reparación y squash en Fy S. Estas variantes crean una nueva confirmación como las variantes "no instantáneas", pero luego combinan instantáneamente la confirmación de reparación con la confirmación de destino utilizando rebase, sin que tenga que invocar otro comando.

"Arreglo instantáneo" ( c F) es esencialmente lo mismo que "extender HEAD" ( c e), excepto que funciona para cualquier confirmación, no solo HEAD.


Otras lecturas:

tarsius
fuente
¡Claro como el cristal! Gracias, increíble paquete BTW.
Mathieu Marques
1
Bueno, creo que hay algunas partes blandas en la segunda mitad de mi respuesta. Pero para evitar los tendría que duplicar la longitud de esta ya larga respuesta, así que estoy contento de que esto funcione para usted ;-)
tarsius
Gracias por esta respuesta tarsius, esto realmente funciona para mí.
anquegi
La claridad de la primera mitad de esta explicación hace que leer la segunda mitad, que es mucho más difícil de seguir, ¡sea bastante frustrante!
Lyn Headley
git-commitLa página man redirige a la git-rebase(1)que tiene estas líneas: El mensaje de confirmación sugerido para la confirmación plegada es la concatenación de los mensajes de confirmación de la primera confirmación y de aquellos con el comando "squash", pero omite los mensajes de confirmación con la "reparación" mando. IOW, use la reparación si solo quiere arreglar el código en el commit anterior, use squash si también quiere arreglar el mensaje de commit.
Yasushi Shoji
3

git commit --amend –C HEADes el comando Git que deseas buscar, y puedes hacer reparaciones en Magit con C-c C-a.

Ryan
fuente
Estoy usando Magit más reciente, C-c C-aes de una versión anterior (creo). Además, no veo ningún rastro de "enmendar" en el búfer de ayuda ( ?).
Mathieu Marques
Ver la respuesta de Rémi para el equivalente magit 2.x.
npostavs
3

Entonces, un flujo de trabajo es:

  • haz tu cambio
  • c (commit) f (arreglo - seleccione confirmar su arreglo)

Luego

  • r (rebase) -a (autosquash, puede ser predeterminado) i (interactivo)

El autoquash moverá automáticamente todas las confirmaciones de reparación al lugar correcto y las configurará para aplastarlas en la re-base.

stsquad
fuente
Lo único que hice que no dijiste fue poner entre tu primera bala y la segunda. Golpear ime rinde Cannot rebase: Your index contains uncommitted changes. Please commit or stash them.. Excepto que no tengo ningún cambio sin confirmar. : /
Mathieu Marques
Intentó de nuevo después de tirar, Proceed despite merge in rebase range? [c]ontinue, [s]elect other, [a]bort. ¿Está tratando de decirme que mi reparación podría cagar en la próxima fusión?
Mathieu Marques
@MathieuMarques: "Excepto que no tengo cambios no comprometidos" - git cree que sí. Tenga en cuenta que el mensaje sugiere cambios por etapas, no por etapas. Re:, merge in rebasevea ERRORES debajo git help rebase. Sugiero hacer la reparación antes de subir.
npostavs
1

Para enmendar el último commit, es "c a". La reparación es para enmendar algunas confirmaciones anteriores.

Rémi
fuente
En ese caso, cometí A y luego B. Publicación actualizada para mayor claridad.
Mathieu Marques