Cómo recuperar los cambios no comprometidos escondidos

691

Tuve algunos cambios no comprometidos en mi rama de desarrollo y los escondí usando git stash, pero hubo algunos cambios que fueron muy importantes entre aquellos escondidos. ¿Hay alguna forma de recuperar esos cambios?

Además, he realizado algunos cambios en la parte superior de los archivos de código escondido desde entonces.

¿Hay alguna posibilidad de que pueda recuperar los cambios escondidos en una nueva rama si es posible?

Aswathy P Krishnan
fuente
77
¿Has intentado usar 'stash pop'?
robert
No. En realidad soy nuevo en git. Como no estoy completamente al tanto de todos los comandos, ¡no probé nada más! No quiero perder esos cambios.
Aswathy P Krishnan
33
Si no desea perder los cambios escondidos, intente usar 'git stash apply'. Esto aplicará los cambios escondidos a su rama actual, mientras conserva el alijo. Si todo está bien, después de aplicar el alijo, puede soltar el alijo, usando 'git stash drop'
robert
2
@robert Gracias por la respuesta simple en comparación con la respuesta aceptada horriblemente complicada (para un novato).
Saheel Godhane

Respuestas:

1184

La respuesta fácil a la pregunta fácil es git stash apply

Solo echa un vistazo a la rama en la que deseas que se realicen tus cambios y luego git stash apply. Luego use git diffpara ver el resultado.

Una vez que está todo hecho con su cambios en la applyapariencia buena y está seguro de que no es necesario el alijo cualquier más- entonces utilizar git stash droppara deshacerse de él.

Siempre sugiero usar en git stash applylugar de git stash pop. La diferencia es que applydeja el alijo para volver a intentarlo fácilmente apply, o para mirarlo, etc. Si popes capaz de extraer el alijo, también lo hará inmediatamente drop, y si de repente se da cuenta de que desea extraerlo en algún lugar de lo contrario (en una rama diferente), o con --index, o algo así, eso no es tan fácil. Si usted apply, puede elegir cuándo hacerlo drop.

Sin embargo, todo es bastante menor de una manera u otra, y para que un novato git, debería ser casi lo mismo. (¡Y puedes saltarte el resto de esto!)


¿Qué pasa si estás haciendo cosas más avanzadas o más complicadas?

Hay al menos tres o cuatro diferentes "formas de usar git stash", por así decirlo. Lo anterior es para el "camino 1", el "camino fácil":

  1. Comenzó con una rama limpia, estaba trabajando en algunos cambios y luego se dio cuenta de que los estaba haciendo en la rama incorrecta. Solo desea tomar los cambios que tiene ahora y "moverlos" a otra rama.

    Este es el caso fácil, descrito anteriormente. Ejecutar git stash save(o simple git stash, lo mismo). Echa un vistazo a la otra rama y úsala git stash apply. Esto hace que git se fusione en tus cambios anteriores, utilizando el mecanismo de fusión bastante poderoso de git. Inspeccione los resultados cuidadosamente (con git diff) para ver si le gustan, y si lo hace, úselos git stash droppara soltar el alijo. Ya terminaste!

  2. Comenzaste algunos cambios y los escondiste. Luego cambiaste a otra rama y comenzaste más cambios, olvidando que tenías los escondidos.

    Ahora desea mantener, o incluso mover, estos cambios, y aplicar su alijo también.

    De hecho git stash save, puede de nuevo, ya que git stashhace una "pila" de cambios. Si haces eso, tienes dos escondites, uno solo llamado, stashpero también puedes escribir, stash@{0}y otro escrito stash@{1}. Use git stash list(en cualquier momento) para verlos a todos. El más nuevo es siempre el más bajo. Cuando tú git stash drop, suelta el más nuevo, y el que se stash@{1}movió a la parte superior de la pila. Si tuvieras aún más, el que se stash@{2}convirtió stash@{1}, y así sucesivamente.

    Puede applyy luego dropun alijo específico también git stash apply stash@{2}, y así sucesivamente. Al soltar un alijo específico, se vuelven a numerar solo los de mayor número. De nuevo, el que no tiene un número también lo es stash@{0}.

    Si acumula muchos alijos, puede volverse bastante desordenado (¿era el alijo que quería stash@{7}o era stash@{4}? Espere, acabo de empujar otro, ¿ahora son 8 y 5?). Personalmente, prefiero transferir estos cambios a una nueva sucursal, porque las sucursales tienen nombres, y cleanup-attempt-in-Decemberpara mí significa mucho más que eso stash@{12}. (El git stashcomando toma un mensaje de guardado opcional, y esos pueden ayudar, pero de alguna manera, todos mis escondites terminan nombrados WIP on branch).

  3. (Extra avanzado) Ha utilizado git stash save -p, o ha git addinsertado cuidadosamente y / o git rmeditado bits específicos de su código antes de ejecutarlo git stash save. Tenía una versión en el área oculta de índice / preparación y otra versión (diferente) en el árbol de trabajo. Quieres preservar todo esto. Así que ahora usa git stash apply --index, y eso a veces falla con:

    Conflicts in index.  Try without --index.
    
  4. Estás utilizando git stash save --keep-indexpara probar "lo que se comprometerá". Este está más allá del alcance de esta respuesta; vea esta otra respuesta de StackOverflow en su lugar.

Para casos complicados, recomiendo comenzar primero en un directorio de trabajo "limpio", confirmando cualquier cambio que tenga ahora (en una nueva rama si lo desea). De esa manera, el "lugar" en el que los está aplicando, no tiene nada más, y solo intentará los cambios escondidos:

git status               # see if there's anything you need to commit
                         # uh oh, there is - let's put it on a new temp branch
git checkout -b temp     # create new temp branch to save stuff
git add ...              # add (and/or remove) stuff as needed
git commit               # save first set of changes

Ahora estás en un punto de partida "limpio". O tal vez se parece más a esto:

git status               # see if there's anything you need to commit
                         # status says "nothing to commit"
git checkout -b temp     # optional: create new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

Lo más importante para recordar es que el "alijo" es una confirmación, es solo una confirmación un poco "divertida / extraña" que no está "en una rama". La applyoperación analiza lo que cambió el commit e intenta repetirlo donde sea que esté ahora. El alijo todavía estará allí (lo applymantiene cerca), por lo que puede mirarlo más, o decidir que este era el lugar incorrecto applye intentarlo de manera diferente, o lo que sea.


Cada vez que tenga un alijo, puede usar git stash show -ppara ver una versión simplificada de lo que está en el alijo. (Esta versión simplificada solo mira los cambios del "árbol de trabajo final", no los cambios guardados en el índice que se --indexrestauran por separado). El comando git stash apply, sin --index, solo intenta hacer esos mismos cambios en su directorio de trabajo ahora.

Esto es cierto incluso si ya tiene algunos cambios. El applycomando se complace en aplicar un alijo a un directorio de trabajo modificado (o al menos, tratar de aplicarlo). Puedes, por ejemplo, hacer esto:

git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

Puede elegir el orden de "solicitud" aquí, seleccionando las reservas particulares para aplicar en una secuencia particular. Sin embargo, tenga en cuenta que cada vez que básicamente realiza una "fusión de git", y como lo advierte la documentación de fusión:

Se desaconseja ejecutar git merge con cambios no triviales no confirmados: aunque sea posible, puede dejarlo en un estado difícil de abandonar en caso de conflicto.

Si comienza con un directorio limpio y solo está haciendo varias git applyoperaciones, es fácil retroceder: use git reset --hardpara volver al estado limpio y cambiar sus applyoperaciones. (Por eso recomiendo comenzar primero en un directorio de trabajo limpio, para estos casos complicados).


¿Qué pasa con el peor de los casos posibles?

Digamos que estás haciendo un montón de cosas avanzadas de Git, y has hecho un alijo, y quieres hacerlo git stash apply --index, pero ya no es posible aplicar el alijo guardado --index, porque la rama ha divergido demasiado desde el momento en que lo guardaste.

Esto es para lo que git stash branchsirve.

Si tu:

  1. revisa la confirmación exacta en la que estabas cuando hiciste el original stash, luego
  2. crear una nueva sucursal, y finalmente
  3. git stash apply --index

el intento de volver a crear los cambios definitivamente va a trabajar. Esto es lo que hace. (Y luego deja caer el alijo ya que se aplicó con éxito).git stash branch newbranch


Algunas palabras finales sobre --index(¿qué diablos es eso?)

Lo que --indexhace es simple de explicar, pero un poco complicado internamente:

  • Cuando tiene cambios, tiene que git add(o "ponerlos en escena") antes de commiting.
  • Por lo tanto, cuando ejecutó git stash, es posible que haya editado ambos archivos fooy zorg, pero solo haya organizado uno de ellos.
  • Por lo tanto, cuando solicite recuperar el alijo, podría ser bueno si son git addlas addcosas ed y no git add las cosas no agregadas. Es decir, si addeditó foopero no zorgregresó antes de hacerlo stash, podría ser bueno tener exactamente la misma configuración. Lo que fue escenificado, nuevamente debe ser escenificado; lo que se modificó pero no se organizó, nuevamente se debe modificar pero no se organizó.

La --indexbandera de applyintenta configurar las cosas de esta manera. Si su árbol de trabajo está limpio, esto generalmente funciona. Sin embargo, si su árbol de trabajo ya tiene material addeditado, puede ver cómo puede haber algunos problemas aquí. Si se excluye --index, la applyoperación no intenta preservar toda la configuración preparada / no preparada. En cambio, solo invoca la maquinaria de fusión de git, usando el commit del árbol de trabajo en la "bolsa de escondite" . Si no le importa conservar las etapas o no, dejar de lado --indexhace que sea mucho más fácil git stash applyhacer lo suyo.

torek
fuente
2
No entiendo tu comentario. ¿Quieres decir: corriste git stash pop? ¿O quieres decir: has editado algunos archivos, pero aún no has git stashvuelto a ejecutarlos ? ¿O quieres decir algo completamente diferente?
torek
1
Si. Tenga en cuenta que, en mi edición (larga), recomiendo confirmar lo que tiene ahora antes de hacer applyun alijo. No tiene que hacer esto, pero hace que las cosas sean mucho más simples de ver. Puede usar rebase -ipara aplastar múltiples confirmaciones, o seleccionar cambios particulares, o lo que sea, más adelante.
torek
1
Sí: git stash apply --index(recuerda los dos guiones). Si lo dejas afuera --index, no es gran cosa; el único punto --indexes mantener la configuración por etapas / por etapas. (Probablemente no tenía ninguna configuración especial en primer lugar). Luego git status, etc., y agregue / confirme como desee, etc. Cuando (y solo cuando) haya terminado con el alijo, úselo git stash droppara descartarlo.
torek
1
Como siempre que se mantenga (no hacerlo dropo pop) el alijo, siempre se tiene la seguridad de código escondido original en una confirmación, porque un alijo es una confirmación! Si desea recuperarlo exactamente, pero en una rama, úselo git stash branch(consulte la sección anterior o el libro Pro Git en la respuesta de Shunya ). Entonces puede git checkoutesa rama, o git cherry-pickel compromiso de esa rama, etc.
torek
2
@ChuckWolber: las convenciones de nomenclatura de Git dejan mucho que desear (¿cuántos significados diferentes podemos asignar a las palabras "remoto", "seguimiento" y "rama" ?!). Sin embargo, vale la pena señalar que puedes aplicar un alijo a algo no relacionado con el alijo original.
torek
57
git stash pop

pondrá todo de nuevo en su lugar

como se sugiere en los comentarios, puede usar git stash branch newbranchpara aplicar el alijo a una nueva rama, que es lo mismo que ejecutar:

git checkout -b newbranch
git stash pop
Stefano Falasca
fuente
Gracias por la ayuda. ¿Puedo obtener esos cambios en una nueva sucursal? En este momento estoy en la rama de desarrollo
Aswathy P Krishnan
3
git stash branch newbranch, creará una nueva rama con los cambios escondidos.
robert
3
@robert: de git stash branch newbranchhecho lo hará; pero tenga en cuenta que crea la nueva rama con su conjunto primario en el commit que estaba HEADen el momento en que stashse realizó. En otras palabras, es para cuando regrese después de una larga sesión de pirateo o lo que sea, mire el desastre y decida "Debería haberlo puesto en una rama, en lugar de esconderlo" :-)
torek
He editado mi pregunta. Me gustaría obtener esos cambios en una nueva sucursal si es posible.
Aswathy P Krishnan
1
A veces solo quieres la respuesta TLDR :)
sachinruk
24

Para simplificar esto, tiene dos opciones para volver a aplicar su alijo:

  1. git stash pop - Restaurar de nuevo al estado guardado, pero elimina el alijo del almacenamiento temporal.
  2. git stash apply - Restaura de nuevo al estado guardado y deja la lista oculta para una posible reutilización posterior.

Puede leer con más detalle sobre las reservas de git en este artículo.

Nesha Zoric
fuente
19

Para verificar el contenido de tu alijo: -

lista de alijo git

aplicar un alijo particular no de la lista de alijo: -

git alijo aplicar alijo @ {2}

o para aplicar solo el primer alijo: -

git stash pop

Nota: git stash pop eliminará el alijo de su lista de escondite, mientras que git stash no se aplicará. Así que úsalos en consecuencia.

Shivansh Rajolia - HeLleR
fuente
2

En mac esto funcionó para mí:

lista de alijo git (ver todos tus alijos)

git stash list

se aplica git stash (solo el número que desea de su lista de alijo)

Me gusta esto:

git stash apply 1
Zack
fuente
0

puede guardar los cambios no confirmados usando "git stash" y luego pasar a una nueva rama usando "git checkout -b" y luego aplicar los commits escondidos "git stash apply"

S.Sandeeptha
fuente