¿Qué muestra la syntax incorrecta de `git stash show -p @ {0}` show (en lugar de usar el correcto `stash @ {0}`)

Estaba jugando con escondites en git y encontré un comportamiento aparentemente extraño.

Después de crear una serie de escondites, quería ver lo que había en ellos. Ejecuté git stash show -p y me mostró una diferencia del último alijo como uno esperaría. Luego, quería confirmar que el índice 0 se refería al alijo más reciente, por lo que (incorrectamente) ejecuté git stash show -p @{0} . Esto me dio el siguiente error:

 fatal: ambiguous argument '': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]' 

Lo suficientemente justo. Pero lo extraño es que luego me dio un cambio de un montón de cambios que no reconocí y que no existían en ninguno de mis escondites.

¿A qué se refería @{0} en este context y de dónde provenía esa diferencia?

Para ampliar un poco la respuesta de kostix , el código de git stash usa los siguientes principios:

  • "El" escondite (el pnetworkingeterminado) se identifica con el nombre refs/stash , por lo que stash@{ number } es una input de reflog para esta reference.
  • Cada alijo está compuesto en la práctica de dos (o a veces tres) confirmaciones, como se muestra en el diagtwig de ¿Es esta una visualización válida de la operación "git stash"? La reference de stash apunta a la confirmación del directory de trabajo o del tree de trabajo, que tiene dos (o tres si la tercera confirmación está presente) confirmaciones principales. Esto significa que si la confirmación del tree de trabajo se trata como si fuera una confirmación periódica realizada por los commands regulares de Git, simplemente sería una confirmación de fusión. (En realidad, tratarlo como una fusión ordinaria puede producir efectos peculiares, por lo que es mejor usar el command git stash para trabajar con él).

Este segundo punto, que es un detalle de implementación, afecta no obstante al código de git stash . En particular, git stash creerá que cualquier commit es un alijo válido si y solo si se trata de un commit de fusión. En realidad, no requiere que la confirmación se nombre a través de refs/stash o una de las inputs de reflog correspondientes.

Si escribe stash@{1} , las reglas tal como se describen en gitrevisions normalmente encontrarán refs refs/stash y extraerán la input 1-th de reflog (es decir, la primera, sin contar la input stash@{0} , que técnicamente no es ' t una input de reajuste en absoluto: Git simplemente recupera el valor de la reference en sí, en lugar de una input del reflog).

Asumiendo que stash@{1} existe, esto nombrará uno de los commits del tree de trabajo del escondite, que será un commit de fusión. El código de git stash verifica que la confirmación que ha nombrado es "similar a un alijo", es decir, tiene la forma prescrita.

Pero esto también significa que si ejecuta algunos de los subcommands de git stash (como show o apply ) usando un ID de hash, o un nombre de twig, o cualquier otro nombre aceptable para el código de revisión de revisión, incluido un reflog normal como reference como @{0} , que significa "el valor extraído de HEAD": el código oculto intentará hacer lo suyo con ese compromiso.

Si ese commit supera la testing "is stash-like", el código de ocultación lo tratará como si fuera un alijo. Dado que la testing "es similar a un stash" es básicamente "es un commit de fusión", lo que sucede con git stash show @{0} o git stash show HEAD es que si el commit actual es una fusión, git stash show tiende a mostrar parte de eso (técnicamente simplemente diff HEAD^1 contra HEAD ). Si no se trata de un commit de fusión, el git stash show debería quejarse y abandonar:

 'HEAD' is not a stash-like commit 

pero las versiones anteriores de Git no siempre son tan inteligentes. Si tu Git es verdaderamente antiguo, puede intentar mostrar algún alijo existente, pasando los arguments adicionales a git diff que se quejará de ellos.

Desde la página de manual de gitrevisions(7) (puede ejecutar git help revisions ):

@{<n>} , por ej. @{1}

Puede usar la construcción @ con una parte de ref vacía para get una input de reflog de la twig actual. Por ejemplo, si está en la twig blabla , @{1} significa lo mismo que blabla@{1} .