¿Cómo revertir aplicar un alijo?

233

Tengo un pequeño parche guardado en mi escondite de git. Lo he aplicado a mi copia de trabajo usando git stash apply. Ahora, me gustaría retroceder esos cambios aplicando el parche en reversa (algo así como lo git revertque haría pero en contra del alijo).

¿Alguien sabe como hacer esto?

Aclaración: hay otros cambios en mi copia de trabajo. Mi caso particular es difícil de describir, pero puede imaginarse algún código de depuración o experimental que esté en el escondite. Ahora está mezclado en mi copia de trabajo con algunos otros cambios y me gustaría ver el efecto con y sin los cambios del alijo.

No parece que stash lo admita actualmente, pero git stash apply --reversesería una buena característica.

Pat Notz
fuente
1
¿No puede simplemente crear un parche invertido al diferenciar entre la revisión actual y la anterior? ¿Y luego aplicar esa?
ralphtheninja
¿Hay cambios en el árbol de trabajo que no sean el alijo aplicado?
Greg Bacon
Agregando esto aquí, ... se suponía que era una pregunta frecuente, no una pregunta ... stackoverflow.com/questions/59973103/…
Don Thomas Boyle

Respuestas:

188

Según la página de manual de git-stash , "Un alijo se representa como un commit cuyo árbol registra el estado del directorio de trabajo, y su primer padre es el commit en el HEADmomento en que se creó el alijo", y git stash show -pnos da "los cambios registrados en el alijo como diferencia entre el estado oculto y su padre original.

Para mantener sus otros cambios intactos, use git stash show -p | patch --reverselo siguiente:

$ git init
Initialized empty Git repository in /tmp/repo/.git/

$ echo Hello, world >messages

$ git add messages

$ git commit -am 'Initial commit'
[master (root-commit)]: created 1ff2478: "Initial commit"
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 messages

$ echo Hello again >>messages

$ git stash

$ git status
# On branch master
nothing to commit (working directory clean)

$ git stash apply
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   messages
#
no changes added to commit (use "git add" and/or "git commit -a")

$ echo Howdy all >>messages

$ git diff
diff --git a/messages b/messages
index a5c1966..eade523 100644
--- a/messages
+++ b/messages
@@ -1 +1,3 @@
 Hello, world
+Hello again
+Howdy all

$ git stash show -p | patch --reverse
patching file messages
Hunk #1 succeeded at 1 with fuzz 1.

$ git diff
diff --git a/messages b/messages
index a5c1966..364fc91 100644
--- a/messages
+++ b/messages
@@ -1 +1,2 @@
 Hello, world
+Howdy all

Editar:

Una mejora ligera para esto es usar git applyen lugar del parche:

git stash show -p | git apply --reverse

Alternativamente, también puede usar git apply -Rcomo una forma abreviada de git apply --reverse.

He estado encontrando esto realmente útil últimamente ...

Greg Bacon
fuente
2
Genial gracias. Parece que esto podría ser una buena característica para el alijo.
Pat Notz
55
Sí, git apply -Res una mejora, al menos para mí en mi ventana de Windows con git bash, ya que patch --reversetuve problemas para localizar el archivo para parchear (no tengo ni idea de por qué funcionó la alternativa). +1 y buena explicación
hakre
¿No sería mejor agregar --indexasí git stash show -p | git apply --reverse --index? Debido a que ya no necesita agregar en el índice los cambios que se revierten.
theUnknown777
3
@ Greg Bacon, bueno, yo he tratado de pasar por el guión que ha rememorado, pero el parche no cuando me encontré git stash show -p | git apply -R -vcon el mensaje: Checking patch messages... error: while searching for: Hello, world Hello again error: patch failed: messages:1. ¿Sabe lo que podría estar mal?
Max Koretskyi
55
Me sale el error: el parche falló: /src/filename.java:46 error: el parche src / filename.java no se aplica
Tim Boland
83

git stash[save]toma su estado de directorio de trabajo y su estado de índice, y los guarda, configurando el índice y el área de trabajo en HEADversión.

git stash applyrecupera esos cambios, por git reset --hardlo que los eliminaría nuevamente.

git stash poprecupera esos cambios y elimina el cambio oculto superior, por git stash [save]lo que volvería al estado anterior (pre-pop) en este caso.

Jakub Narębski
fuente
82
git checkout -f

eliminará cualquier cambio que no sea de confirmación.

salman
fuente
44
gracias, me ayudas del cambio por etapas que no fue sin aplicación.
Fa.Shapouri
1
Esto fue mucho más simple
Mark A
¡Esto fue asombroso!
Kiran Sk
22

La página de manual de V1 git tenía una referencia sobre la eliminación de la aplicación de un alijo. El extracto está abajo.

La nueva página de manual de git de V2 no incluye ninguna referencia a la eliminación de la aplicación de un alijo, pero el siguiente sigue funcionando bien

Desinstalar un alijo En algunos escenarios de casos de uso, es posible que desee aplicar cambios escondidos, hacer algo de trabajo, pero luego des-aplicar los cambios que originalmente vinieron del alijo. Git no proporciona un comando de desaplicación de escondite, pero es posible lograr el efecto simplemente recuperando el parche asociado con un escondite y aplicándolo en reversa:

$ git stash show -p stash@{0} | git apply -R

Nuevamente, si no especificas un alijo, Git asume el alijo más reciente:

$ git stash show -p | git apply -R

Es posible que desee crear un alias y agregar efectivamente un comando stash-nopply a su Git. Por ejemplo:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
Choco Smith
fuente
1
Por alguna razón, esta sección útil que vinculó " Desaplicar un alijo " se eliminó de la segunda versión, la última versión en este momento es 2.1.146, 2019-04-15- de este libro V2- Herramientas Git: alijo y limpieza . Podría ser porque los autores piensan que hay una mejor manera de hacer esto que parece que no puedo encontrar.
Nad Alaba el
@NadAlaba gracias por el aviso, he actualizado la respuesta para tomar nota de la diferencia entre v1 y v2 ... raro los autores de git eliminaron la sección sobre la no aplicación de un alijo
Choco Smith
13

Esto ya se ha vencido, pero si interpreto el problema correctamente, he encontrado una solución simple, tenga en cuenta que esta es una explicación en mi propia terminología:

git stash [save] guardará los cambios actuales y establecerá su rama actual en el "estado limpio"

git stash list da algo como: stash@{0}: On develop: saved testing-stuff

git apply stash@{0}establecerá la rama actual como antes stash [save]

git checkout .Establecerá la rama actual como después stash [save]

El código que se guarda en el alijo no se pierde, se puede volver a encontrar git apply stash@{0}.

De todos modos, esto funcionó para mí!

Slim Sim
fuente
Solo para estar seguro, apliqué git stash apply --reverseprimero y luego simplemente volví a git stash apply stash@{x}gustarme. Trabajó sin problemas.
Carlos García
3

¿Cómo revertir aplicar un alijo?

Aparte de lo que otros han mencionado, la forma más fácil es hacer primero

git reset HEAD

y luego verifique todos los cambios locales

git checkout . 
Achal
fuente
Esta es, con mucho, la forma más fácil, siempre y cuando no tenga absolutamente ningún trabajo local que desee guardar. Si aplicó el alijo incorrecto a una rama o golpeó conflictos de fusión que no desea resolver, esta es la forma rápida y fácil de deshacerlo revertiendo completamente su conjunto de trabajo a la última confirmación de su rama.
Shadoninja
2

Además de la respuesta de @Greg Bacon, en caso de que se agregaran archivos binarios al índice y formaran parte del alijo usando

git stash show -p | git apply --reverse

puede resultar en

error: cannot apply binary patch to '<YOUR_NEW_FILE>' without full index line
error: <YOUR_NEW_FILE>: patch does not apply

Agregar --binaryresuelve el problema, pero desafortunadamente aún no he descubierto por qué.

 git stash show -p --binary | git apply --reverse
MHosafy
fuente
1

Puede seguir la imagen que compartí para desangrar si tocó accidentalmente el alijo.

Amanpreet Singh
fuente
0

Esto se suma a las respuestas anteriores, pero agrega la búsqueda del alijo git en función del mensaje, ya que el número de alijo puede cambiar cuando se guardan nuevos alijos. He escrito un par de funciones bash:

apply(){
  if [ "$1" ]; then
    git stash apply `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"`
  fi
}
remove(){
  if [ "$1" ]; then
    git stash show -p `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"` | git apply -R
    git status
  fi
}
  1. Crear alijo con nombre (mensaje) $ git stash save "my stash"
  2. Para aplicar nombrado $ apply "my stash"
  3. Para eliminar alijo con nombre $ remove "my stash"
vida ordinaria
fuente