¿Cómo recuperar un alijo caído en Git?


Uso con frecuencia git stash y git stash pop para guardar y restaurar los cambios en mi árbol de trabajo. Ayer tuve algunos cambios en mi árbol de trabajo que había guardado y reventado, y luego hice más cambios en mi árbol de trabajo. Me gustaría volver y revisar los cambios guardados de ayer, pero git stash pop parece eliminar todas las referencias a la confirmación asociada.

Sé que si uso git stash entonces .git / refs / stash contiene la referencia del commit utilizado para crear el stash. Y .git / logs/refs / stash contiene todo el stash. Pero esas referencias se han ido después de git stash pop. Sé que la confirmación todavía está en mi repositorio en algún lugar, pero no se lo que era.

¿Hay una manera fácil de recuperar la referencia de confirmación de stash de ayer?

Tenga en cuenta que esto no es crítico para mí hoy porque tengo copias de seguridad diarias y puedo volver al árbol de trabajo de ayer para obtener mis cambios. ¡Lo pregunto porque debe haber una manera más fácil!

Author: Randall, 2008-09-18

19 answers

Si acaba de abrirlo y el terminal todavía está abierto, todavía tendrá el valor hash impreso por git stash pop en la pantalla (gracias, Dolda).

De lo contrario, puede encontrarlo usando esto para Linux y Unix:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

Y para Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Esto te mostrará todas las confirmaciones en las puntas de tu gráfico de confirmaciones que ya no están referenciadas desde ninguna rama o etiqueta - cada confirmación perdida, incluyendo cada confirmación de stash que hayas creado, será en algún lugar de ese gráfico.

La forma más fácil de encontrar la confirmación de stash que desea es probablemente pasar esa lista a gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

Esto lanzará un navegador de repositorio que le mostrará cada confirmación en el repositorio siempre, independientemente de si es accesible o no.

Puede reemplazar gitk allí con algo como git log --graph --oneline --decorate si prefiere un buen gráfico en la consola en lugar de una aplicación GUI separada.

Para detectar confirmaciones de stash, busque los mensajes de confirmación de este formulario:

WIP on somebranch: commithash Algún viejo mensaje de commit

Nota: El mensaje de confirmación solo estará en esta forma (comenzando con "WIP on") si no proporcionó un mensaje cuando lo hizo git stash.

Una vez que conozcas el hash del commit que deseas, puedes aplicarlo como un stash:

git stash apply $stash_hash

O puede usar el menú contextual en gitk para crear ramas para cualquier confirmación inalcanzable que le interese. Después de eso, puedes hacer lo que quieras con ellos con todas las herramientas normales. Cuando termines, vuelve a volar esas ramas.

 2195
Author: Aristotle Pagaltzis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:54

Si no cerraste el terminal, simplemente mira la salida de git stash pop y tendrás el ID del objeto del alijo caído. Normalmente se ve así:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Tenga en cuenta que git stash drop también produce la misma línea.)

Para recuperar ese alijo, simplemente ejecuta git branch tmp 2cae03e, y lo obtendrás como una rama. Para convertir esto en un alijo, ejecute:

git stash apply tmp
git stash

Tenerlo como una rama también le permite manipularlo libremente; por ejemplo, seleccionarlo o combinarlo.

 617
Author: Dolda2000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-22 23:45:33

Solo quería mencionar esta adición a la solución aceptada. No fue inmediatamente obvio para mí la primera vez que probé este método (tal vez debería haberlo sido), pero para aplicar el stash desde el valor hash, simplemente use "git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Cuando era nuevo en git, esto no estaba claro para mí, y estaba probando diferentes combinaciones de "git show", "git apply", "patch", etc.

 238
Author: Wade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-03 20:28:51

Acabo de construir un comando que me ayudó a encontrar mi confirmación de alijo perdido:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Esto enumera todos los objetos en el .git / objects tree, localiza los que son de tipo commit, luego muestra un resumen de cada uno. Desde este punto solo era cuestión de mirar a través de las confirmaciones para encontrar un "WIP on work: 6a9bb2" apropiado ("work" es mi rama, 619bb2 es una confirmación reciente).

Observo que si utilizo "git stash apply" en lugar de "git stash pop" no tendría este problema, y si utilizo " git stash save message " entonces la confirmación podría haber sido más fácil de encontrar.

Actualización: Con la idea de Nathan, esto se hace más corto:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
 69
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 02:10:13

Para obtener la lista de los alijos que aún están en su repositorio, pero que ya no se pueden alcanzar:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Si le dio un título a su alijo, reemplace "WIP" en -grep=WIP al final del comando con una parte de su mensaje, por ejemplo, -grep=Tesselation.

El comando está greping para " WIP " porque el mensaje de confirmación predeterminado para un stash está en la forma WIP on mybranch: [previous-commit-hash] Message of the previous commit.

 64
Author: Senthil A Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-19 12:01:28

git fsck --unreachable | grep commit debe mostrar el sha1, aunque la lista que devuelve puede ser bastante grande. git show <sha1> mostrará si es la confirmación que desea.

git cherry-pick -m 1 <sha1> fusionará la confirmación en la rama actual.

 37
Author: Nathan Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 02:14:27

Si quieres volver a lanzar un alijo perdido, primero debes encontrar el hash de tu alijo perdido.

Como Aristóteles Pagaltzis sugirió, un git fsck debería ayudarte.

Personalmente uso mi alias log-all que me muestra cada commit (commits recuperables) para tener una mejor visión de la situación:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Puedes hacer una búsqueda aún más rápida si solo buscas mensajes "WIP on".

Una vez que conozca su sha1, simplemente cambie su reflog de alijo para agregar el alijo antiguo :

git update-ref refs/stash ed6721d

Probablemente prefieras tener un mensaje asociado para que un -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

E incluso querrás usar esto como un alias :

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
 23
Author: Colin Hebert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-09 22:18:52

Me gustó el enfoque de Aristóteles, pero no me gustó usar GITK... como estoy acostumbrado a usar GIT desde la línea de comandos.

En su lugar, tomé las confirmaciones colgantes y saqué el código a un archivo DIFF para su revisión en mi editor de código.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Ahora puede cargar el archivo diff/txt resultante (está en su carpeta de inicio) en su editor txt y ver el código real y el SHA resultante.

Entonces solo use

git stash apply ad38abbf76e26c803b27a6079348192d32f52219
 15
Author: Shaheen Ghiassy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-07 20:17:34

En OSX con git v2.6.4, acabo de ejecutar git stash drop accidentalmente, luego lo encontré yendo a través de los siguientes pasos

Si conoces el nombre del alijo entonces usa:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

De lo contrario, encontrará ID del resultado manualmente con:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Luego, cuando encuentre el commit-id, simplemente presione el git stash apply {commit-id}

Espero que esto ayude a alguien rápidamente

 12
Author: Can Tecim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-01 09:57:53

Equivalente a Windows PowerShell usando gitk:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Probablemente hay una forma más eficiente de hacer esto en una sola tubería, pero esto hace el trabajo.

 11
Author: emragins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-07 23:22:05

Quiero agregar a la solución aceptada otra buena manera de pasar por todos los cambios, cuando no tiene gitk disponible o no hay X para la salida.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Entonces usted obtiene todos los diffs para esos hashes mostrados uno tras otro. Presione ' q ' para llegar a la siguiente diferencia.

 10
Author: Phil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-04 12:32:19

¿Por qué la gente hace esta pregunta? Porque todavía no saben o entienden el reflog.

La mayoría de las respuestas a esta pregunta dan comandos largos con opciones que casi nadie recordará. Así que las personas entran en esta pregunta y copian y pegan lo que creen que necesitan y lo olvidan casi inmediatamente después.

Aconsejaría a todos con esta pregunta que simplemente revisen el reflog (git reflog), no mucho más que eso. Una vez que vea esa lista de todas las confirmaciones, hay cien formas de averiguar qué commit estás buscando y elegirlo o crear una rama a partir de él. En el proceso habrás aprendido sobre el reflog y opciones útiles para varios comandos básicos de git.

 10
Author: RobbyD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-26 10:38:18

La respuesta aceptada por Aristóteles mostrará todas las confirmaciones alcanzables, incluidas las confirmaciones no similares a stash. Para filtrar el ruido:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Esto solo incluirá commits que tienen exactamente 3 commits padre (que tendrá un stash), y cuyo mensaje incluye "WIP on".

Tenga en cuenta que si guardó su alijo con un mensaje (por ejemplo, git stash save "My newly created stash"), esto anulará el valor predeterminado "WIP on..." mensaje.

Puede mostrar más información sobre cada confirmación, por ejemplo, mostrar el confirmar mensaje, o pasarlo a git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R
 9
Author: Brad Feehan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-17 04:33:50

No pude obtener ninguna de las respuestas para trabajar en Windows en una ventana de comandos simple (Windows 7 en mi caso). awk, grep y Select-string no fueron reconocidos como comandos. Así que probé un enfoque diferente:

  • primera ejecución: git fsck --unreachable | findstr "commit"
  • copie la salida al bloc de notas
  • find reemplazar "confirmación inalcanzable" por start cmd /k git show

Se verá algo como esto:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • guardar como a .bat archivo y ejecutarlo
  • el script abrirá un montón de comandos windows, mostrando cada commit
  • si ha encontrado el que está buscando, ejecute: git stash apply (your hash)

Puede no ser la mejor solución, pero funcionó para mí

 8
Author: kromakollision,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-28 15:01:39

Lo que vine aquí buscando es cómo recuperar el alijo, independientemente de lo que haya comprobado. En particular, había escondido algo, luego revisé una versión anterior, luego la abrí, pero el alijo no estaba operativo en ese momento anterior, por lo que el alijo desapareció; no pude simplemente hacer git stash para empujarlo de nuevo a la pila. Esto funcionó para mí:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

En retrospectiva, debería haber estado usando git stash apply no git stash pop. Estaba haciendo un bisect y tenía un pequeño parche que quería aplicar en cada paso bisect. Ahora estoy haciendo esto:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.
 4
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-07 15:13:25

Lo recuperó utilizando los siguientes pasos:

  1. Identifique el código hash del alijo eliminado:

    Gitk all all {(git fsck no no-reflog | awk '/dangling commit/ {print 3 3}')

  2. Cherry Elige el Alijo:

    Git cherry-pick-m 1 st stash_hash_code

  3. Resuelve los conflictos si los hay usando:

    Git mergetool

Además, es posible que tenga problemas con el mensaje de confirmación si está utilizando gerrit. Por favor, guarda tu cambios antes de seguir las siguientes alternativas:

  1. Use hard reset a la confirmación anterior y luego vuelva a comprometer este cambio.
  2. También puede guardar el cambio, rebase y volver a comprometerse.
 4
Author: Abhijeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-16 11:20:14

Puede listar todas las confirmaciones inalcanzables escribiendo este comando en terminal -

git fsck --unreachable

Comprobar hash de confirmación inalcanzable -

git show hash

Finalmente se aplica si encuentra el elemento escondido -

git stash apply hash
 4
Author: Vivek Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-07 11:31:52

Otro caso de uso común: ¿Ha intentado aparecer en la rama incorrecta y tiene conflictos?

Todo lo que desea es deshacer el pop pero aún así mantenerlo en la lista de alijo para que pueda pop en la rama correcta.

Para arreglarlo, haga lo siguiente:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Hecho!

 0
Author: dorony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-07 11:41:52

Eliminé accidentalmente el alijo en la aplicación GitUP. Simplemente presione Ctrl + Z para deshacerlo.

Tal vez ayude a alguien;)

 0
Author: Nik Kov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-27 09:52:37