¿Puedo hacer una reversión parcial en GIT

156

¿Es posible revertir un solo archivo o ciertos cambios en un archivo en confirmación de múltiples archivos?

Historia completa cometí un montón de archivos. Una serie de confirmaciones posteriores, alguien que permanecerá sin nombre (JACK !!!) copió un archivo en su repositorio y confirmó varios archivos, sobrescribiendo algunos de los cambios que hice. Quiero revertir el único archivo que se golpeó o mejor aún, entrar y revertir dos cambios en ese archivo. Esto tendrá que ser una confirmación de reversión separada, ya que fue extraída y empujada.

Embrague
fuente
Brian me puso en el camino correcto. Terminé usando git add --patch y luego usando la función de edición dentro del parche para obtener lo que quería.
Embrague
2
Llego bastante tarde al juego, pero creo que encontré la respuesta "correcta" .
ntc2
@ ntc2 Curiosamente, la respuesta aceptada funcionó para mí mucho mejor que la que vinculó: creó conflictos de fusión para que yo los resolviera, en lugar de simplemente no aplicar los parches.
Iiridayn
@liridayn ¿Leíste toda mi respuesta? En la sección "variaciones", afirmo que agregar --3wayresultados en conflictos de fusión en lugar de no aplicar parches.
ntc2

Respuestas:

204

Puede revertir la confirmación sin crear una nueva agregando la opción '--no-commit'. Esto deja todos los archivos revertidos en el área de preparación. A partir de ahí, realizaría un reinicio por software y agregaría los cambios que realmente quería. Para un ejemplo de flujo de trabajo:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit
bobDevil
fuente
42
Después del restablecimiento parcial, también puede git add -piniciar una sesión interactiva que le permite agregar selectivamente fragmentos de archivos, en lugar de archivos completos. (También hay git reset -pcambios selectivamente en el escenario. Es bueno saberlo, pero probablemente no lo que quieres en este escenario.)
Stéphan Kochen
1
Esto era exactamente lo que estaba buscando: volver a la copia de trabajo, seleccionar trozos interactivamente, comprometerse. Te mereces un gran beso de hombre salado por eso: *
das_weezul
Otra solución inspirada por éste sería revert, reset, stash -p(escondite "se cancela que yo no quiero hacer actualy"), addel resto,commit
Cyril CHAPON
82

Puede aplicar interactivamente la versión anterior de un archivo con el checkoutcomando

Por ejemplo, si sabe COMMITdónde se eliminó el código para volver a agregar, puede ejecutar el siguiente comando:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git le pedirá que vuelva a agregar los trozos que faltan en la versión actual del archivo. Puede usar epara crear un parche del cambio antes de aplicarlo nuevamente.

cmcginty
fuente
¡Muy útil si solo quiere revertir parte del archivo! Básicamente, para obtener trozos de la cabeza,git checkout -p path/to/file
falstaff
40

Puede verificar manualmente el contenido antiguo y bueno de los archivos que desea revertir usando git checkout. Por ejemplo, si desea volver my-important-filea la versión que estaba en la versión abc123, puede hacer

git checkout abc123 -- my-important-file

Ahora tiene el contenido anterior de la parte my-important-fileposterior, e incluso puede editarlos si lo desea, y comprometerse como de costumbre para realizar una confirmación que revertirá los cambios que realizó. Si solo desea revertir algunas partes de su compromiso, use git add -ppara seleccionar solo unos pocos trozos del parche que está comprometiendo.

Brian Campbell
fuente
19
Esto no es un revert, solo está recuperando una versión anterior del archivo. Un correcto reverteliminará las modificaciones de confirmación incorrecta dentro del archivo, incluso si se ha modificado varias veces desde esa confirmación incorrecta, y no desea perder esas modificaciones.
Totor
2
Totor, mira mi respuesta. Puede usar '-p' para guardar modificaciones. La respuesta está muy cerca de esta en realidad.
cmcginty
1
O puedes combinar esto en git checkout -p.
Léo Lam
31

Encontré una manera de hacer esto en la lista de correo de Git:

git show <commit> -- <path> | git apply --reverse

Fuente: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Variaciones

Ese comando falla (sin causar cambios) si el parche no se aplica limpiamente, pero en --3waysu lugar obtiene conflictos que luego puede resolver manualmente (en este caso, la respuesta de Casey podría ser más práctica):

git show <commit> -- <path> | git apply --reverse --3way

También puede usar esto para revertir parcialmente confirmaciones múltiples, por ejemplo:

git log -S<string> --patch | git apply --reverse

para revertir archivos con cambios que coincidan <string>en cualquier confirmación. Esto es exactamente lo que necesitaba en mi caso de uso (algunas confirmaciones separadas introdujeron cambios similares en diferentes archivos, junto con cambios en otros archivos de formas no relacionadas que no quería revertir).

Si ha diff.noprefix=trueconfigurado en su, ~/.gitconfigentonces necesita agregar -p0al git applycomando, por ejemplo

git show <commit> -- <path> | git apply -p0 --reverse
ntc2
fuente
Esta respuesta es mucho mejor que la aceptada: "mejor aún, entre y revierta dos cambios en ese archivo".
reescrito el
Quería revertir solo una parte de una confirmación, así que hice: (1) git show ... > foo.txt (2) editar foo.txtpara eliminar las diferencias que no quería revertir (3) git apply --reverse foo.txt para revertir las diferencias que todavía figuran en la lista foo.txt.
cxw
Agregar --binary --full-index a git show part también podría ser una variación útil
Laurynas Biveinis