Cómo agregar un archivo modificado a una confirmación anterior (no la última) en Git

461

Cambié varias cosas durante la última hora y las comprometí paso a paso, pero me di cuenta de que olvidé agregar un archivo modificado hace algunas confirmaciones.

El registro se ve así:

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

¿Algunas ideas?

leen
fuente
1
¿Esencialmente un duplicado de Cómo modificar una confirmación especificada?
Dan Dascalescu el

Respuestas:

694

Uso git rebase. Específicamente:

  1. Use git stashpara almacenar los cambios que desea agregar.
  2. Uso git rebase -i HEAD~10(o la cantidad de confirmaciones que desee ver).
  3. Marque el commit en cuestión ( a0865...) para editar cambiando la palabra pickal comienzo de la línea en edit. No elimine las otras líneas ya que eso eliminaría los commits. [^ Vimnote]
  4. Guarde el archivo de rebase, y git volverá al shell y esperará a que arregle esa confirmación.
  5. Explota el alijo usando git stash pop
  6. Agregue su archivo con git add <file>.
  7. Modifique el compromiso con git commit --amend --no-edit.
  8. Haz una git rebase --continueque reescriba el resto de tus commits contra el nuevo.
  9. Repita desde el paso 2 en adelante si ha marcado más de una confirmación para editar.

[^ vimnote]: si está utilizando vim, deberá presionar la Inserttecla para editar y luego Escescribir :wqpara guardar el archivo, salir del editor y aplicar los cambios. Alternativamente, puede configurar un editor git commit fácil de usar con git config --global core.editor "nano".

Greg Hewgill
fuente
23
¿Qué sucede si tiene cambios no escalonados que desea agregar a la edición? Si los guardo, no podría git add.
Sam
15
Sam, simplemente puedes quitar los cambios mientras estás en el commit en cuestión, funcionará bien.
omnikron
17
Nota: Cuando marque la confirmación con edit, NO ELIMINE las otras confirmaciones que figuran en el archivo Si lo hace, las confirmaciones se eliminarán y tendrá que seguir estos pasos para recuperarlas.
David Tuite
2
Con respecto a lo que dijo @DavidTuite, un hábito mío al hacer cosas en git que no estoy seguro de cómo resultará es crear una rama "branchname-ref" para guardar el estado actual de la línea de tiempo en caso de que arruine las cosas. Cuando termino, lo borro.
Raphael
1
En el paso 6, incluya el. (punto) en el comando. Comando correcto:git add .
Tom
323

Para "arreglar" una confirmación anterior con un pequeño cambio, sin cambiar el mensaje de confirmación de la confirmación anterior, ¿dónde OLDCOMMITestá algo así como 091b73a:

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

También puede usar git commit --squash=OLDCOMMITpara editar el antiguo mensaje de confirmación durante el rebase.


  • git rebase --interactiveAparecerá un editor de texto (que se puede configurar ) para confirmar (o editar) la secuencia de instrucciones de rebase . Hay información para cambios de instrucciones de rebase en el archivo; simplemente guarde y salga del editor ( :wqenvim ) para continuar con la nueva versión.
  • --autosquashpondrá automáticamente las --fixup=OLDCOMMITconfirmaciones en el orden deseado. Tenga en cuenta que --autosquashsolo es válido cuando --interactivese utiliza la opción.
  • El ^in OLDCOMMIT^significa que es una referencia al commit justo antes OLDCOMMIT.

Los pasos anteriores son buenos para verificar y / o modificar la secuencia de instrucciones de rebase , pero también es posible omitir / automatizar el editor de texto de rebase interactivo mediante:

Ver git commit y git rebase . Como siempre, al reescribir el historial de git , solo debe corregir o confirmar los compromisos que aún no ha publicado a nadie más (incluidos los usuarios aleatorios de Internet y los servidores de compilación).

Joel Purra
fuente
18
Mucho más claro que las otras opciones, y funcionó a las
mil maravillas
55
@ Jonás: el editor no está abierto para editar el mensaje de confirmación, sino para confirmar (o editar) los pasos de cambio de versión . No se puede evitar; --autosquashsolo es válido cuando --interactivese usa la opción .
Joel Purra
55
Al usar esta solución, estoy atascado git mostrando VIM. Mi problema es que no sé cómo usar VIM. Cómo diablos salgo de eso, cómo puedo controlar esto, esto es tan confuso.
Neon Warge
2
@NeonWarge: el editor de elección es configurable usando, por ejemplo git config --global core.editor "pico". Hay varias otras formas de configurar git y / o cambiar el editor predeterminado de su sistema, etc.
Joel Purra
2
one line nice alias here
idanp
61

Con git 1.7, hay una manera muy fácil de usar git rebase:

organizar sus archivos:

git add $files

crear un nuevo mensaje de confirmación y reutilizar la confirmación de su confirmación "rota"

git commit -c master~4

anteponer fixup!en la línea de asunto (o squash!si desea editar commit (mensaje)):

fixup! Factored out some common XPath Operations

use git rebase -i --autosquashpara arreglar su confirmación

knittl
fuente
2
+1. Buen uso de la nueva directiva de reparación (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/…
VonC
@knittl Estaba probando su método para agregar otro archivo a una antigua confirmación mía (no presionada), pero cuando vuelvo a componer, obtengo You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'y si luego uso git rebase -i --autosquash, obtengo una nooplínea de asunto, volviendo a asignar la confirmación en sí misma. ¿Alguna idea de lo que hago mal?
oschrenk
77
@oschrenk: debe proporcionar un compromiso para el que desea cambiar la base, por ejemplogit rebase -i --autosquash HEAD~10
knittl
1
Buena respuesta, pero también necesitaba agregar un commit contra el cual rebase. Sería genial si pudieras actualizarlo.
Paul Odeon
@PaulOdeon: No entiendo tu pregunta. ¿Qué estás tratando de hacer y dónde tienes problemas?
knittl
8

Puede probar una rebase --interactivesesión para modificar su confirmación anterior (siempre que no haya enviado esas confirmaciones a otro repositorio).

A veces la cosa arreglada en b.2. no se puede modificar a la confirmación no perfecta que corrige, porque esa confirmación está enterrada profundamente en una serie de parches .
Para eso es exactamente el rebase interactivo: utilícelo después de muchas "a" sy "b" s, reorganizando y editando commits, y aplastando varios commits en uno.

Comience con la última confirmación que desea conservar tal cual:

git rebase -i <after-this-commit>

Se activará un editor con todos los commits en su rama actual (ignorando los commits de fusión), que vienen después del commit dado.
Puede reordenar las confirmaciones de esta lista al contenido de su corazón, y puede eliminarlas. La lista se ve más o menos así:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Las descripciones en línea son puramente para su placer; git rebase no los verá sino a los nombres de confirmación ("deadbee" y "fa1afe1" en este ejemplo), así que no elimine ni edite los nombres.

Al reemplazar el comando "elegir" con el comando "editar", puede indicarle a git rebase que se detenga después de aplicar ese compromiso, de modo que pueda editar los archivos y / o el mensaje de compromiso, modificar el compromiso y continuar el cambio de nombre .

VonC
fuente