Pregunta ¿Cómo recuperar un alijo abandonado en Git?


Uso con frecuencia git stash y git stash pop para guardar y restaurar cambios en mi árbol de trabajo. Ayer tuve algunos cambios en mi árbol de trabajo que había escondido y reventado, y luego hice más cambios en mi árbol de trabajo. Me gustaría volver y revisar los cambios escondidos 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 de la confirmación utilizada para crear el alijo. Y .git / logs / refs / stash contiene todo el alijo. Pero esas referencias se han ido después git stash pop. Sé que el compromiso todavía está en mi repositorio en alguna parte, pero no sé qué era.

¿Hay alguna 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 estoy preguntando porque debe haber una manera más fácil!


1331
2017-09-18 01:59


origen


Respuestas:


Si acaba de abrirlo y la terminal todavía está abierta, lo hará todavía tiene el valor de 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 le mostrará todas las confirmaciones en las puntas de su gráfico de compromiso, que ya no se referencian desde ninguna rama o etiqueta: cada compromiso perdido, incluyendo cada compromiso de escondite que haya creado alguna vez, estará en algún lugar de ese gráfico.

La forma más fácil de encontrar el compromiso de ocultación 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 te muestra cada compromiso en el repositorio alguna vez, independientemente de si es alcanzable o no.

Puedes reemplazar gitk allí con algo así como git log --graph --oneline --decorate si prefiere un buen gráfico en la consola a través de una aplicación GUI separada.

Para detectar confusiones ocultas, busca los mensajes de confirmación de este formulario:

WIP en somebranch: commithash Algún mensaje de compromiso antiguo

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

Una vez que conozca el hash de la confirmación que desea, puede aplicarlo como un alijo:

git stash apply $ stash_hash

O puede usar el menú contextual en gitk para crear ramas para cualquier compromiso inalcanzable que le interese. Después de eso, puede hacer lo que quiera con ellas con todas las herramientas normales. Cuando hayas terminado, solo sopla esas ramas de nuevo.


2151
2017-09-18 11:38



Si no cerró la terminal, solo mire la salida de git stash pop y tendrás la ID del objeto del alijo arrojado. Por lo general, 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 escondite, solo ejecuta git branch tmp 2cae03ey lo obtendrás como una sucursal. Para convertir esto a un alijo, ejecuta:

git stash apply tmp
git stash

Tenerlo como una rama también te permite manipularlo libremente; por ejemplo, para seleccionarlo o fusionarlo.


597
2017-10-21 03:13



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 alijo del valor hash, simplemente usa "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.


231
2018-03-03 20:28



Acabo de construir un comando que me ayudó a encontrar mi commit de stash 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 árbol .git / objects, localiza los que son de tipo commit, luego muestra un resumen de cada uno. A partir de este punto, solo fue cuestión de revisar los compromisos para encontrar un "WIP en trabajo apropiado: 6a9bb2" ("trabajo" es mi rama, 619bb2 es un compromiso reciente).

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

Actualización: con la idea de Nathan, esto se vuelve más corto:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

68
2017-09-18 02:10



Para obtener la lista de depósitos que todavía 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 escondite, reemplace "WIP" en -grep=WIP al final del comando con una parte de su mensaje, p. -grep=Tesselation.

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


56
2018-05-04 06:42



git fsck --unreachable | grep commit debería 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.


36
2017-09-18 02:08



Si quiere restash un escondite perdido, primero necesita encontrar el hash de su escondite perdido.

Como Aristóteles Pagaltzis sugirió una git fsck debería ayudarte

Personalmente utilizo mi log-all alias que me muestra cada confirmación (confirmaciones 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)

Puede hacer una búsqueda aún más rápida si solo busca mensajes de "WIP encendido".

Una vez que conozca su sha1, simplemente cambie su reflog de escondite para agregar el viejo escondite:

git update-ref refs/stash ed6721d

Probablemente prefiera tener un mensaje asociado para que -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
2018-06-23 14:20



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

En cambio, tomé los commits colgantes y envié 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 de texto y ver el código real y el SHA resultante.

Entonces solo usa

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

15
2018-01-07 20:17