Como una pequeña explicación adicional, tenga en cuenta que git stash
hace dos confirmaciones o tres confirmaciones. El valor predeterminado es dos; obtienes tres si usas cualquier ortografía de las opciones --all
o --include-untracked
.
Estas dos o tres confirmaciones son especiales en una forma importante: no están en ninguna rama. Git los ubica a través del nombre especial stash
. 1 Sin embargo, lo más importante es lo que Git te permite, y te obliga , hacer con estas dos o tres confirmaciones. Para entender esto, necesitamos mirar qué hay en esas confirmaciones.
¿Qué hay dentro de un escondite?
Cada confirmación puede enumerar una o más confirmaciones principales . Estos forman un gráfico, donde las confirmaciones posteriores apuntan a las anteriores. El alijo normalmente contiene dos confirmaciones, que me gusta llamar i
para el contenido del índice / área de ensayo y w
para el contenido del árbol de trabajo. Recuerde también que cada confirmación contiene una instantánea. En una confirmación normal, esta instantánea se realiza a partir del contenido del índice / área de ensayo. ¡Así que el i
compromiso es de hecho un compromiso perfectamente normal! Simplemente no está en ninguna rama:
...--o--o--o <-- branch (HEAD)
|
i
Si está haciendo un alijo normal, el git stash
código lo hace w
ahora copiando todos sus archivos de árbol de trabajo rastreados (en un índice auxiliar temporal). Git establece que el primer padre de esta w
confirmación apunte a la HEAD
confirmación y el segundo padre apunte a la confirmación i
. Por último, se establece stash
para apuntar a este w
compromiso:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Si agrega --include-untracked
o --all
, Git realiza una confirmación adicional u
, entre hacer i
y w
. El contenido de la instantánea u
son aquellos archivos que no se rastrean pero no se ignoran ( --include-untracked
), o archivos que no se rastrean incluso si se ignoran ( --all
). Esta u
confirmación adicional no tiene padre, y luego, cuando se git stash
realiza w
, establece w
el tercer padre en esta u
confirmación, de modo que obtiene:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
Git también, en este punto, elimina los archivos del árbol de trabajo que terminaron en la u
confirmación (usando git clean
para hacer eso).
Restaurar un alijo
Cuando vas a restaurar un alijo, tienes la opción de usarlo --index
o no. Esto le dice git stash apply
(o cualquiera de los comandos que usa internamente apply
, como pop
) que debe usar el i
compromiso para intentar modificar su índice actual. Esta modificación se realiza con:
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(más o menos; hay un montón de detalles importantes que se interponen en el camino de la idea básica aquí).
Si omite --index
, git stash apply
ignora por completo la i
confirmación.
Si el alijo tiene solo dos confirmaciones, git stash apply
ahora puede aplicar la w
confirmación. Hace esto llamando a git merge
2 (sin permitirle confirmar o tratar el resultado como una fusión normal), usando la confirmación original en la que se hizo el alijo ( i
el padre y w
el primer padre) como base de fusión, w
como el --theirs
commit, y su compromiso actual (HEAD) como el objetivo de la fusión. Si la fusión tiene éxito, todo está bien, bueno, al menos Git así lo cree, y la git stash apply
misma tiene éxito. Si solía git stash pop
aplicar el alijo, el código ahora elimina el alijo. 3 Si la fusión falla, Git declara que la aplicación ha fallado. Si usastegit stash pop
, el código conserva el alijo y entrega el mismo estado de falla que para git stash apply
.
Pero si tiene esa tercera confirmación, si hay una u
confirmación en el alijo que está aplicando, ¡entonces las cosas cambian! No hay opción para fingir que la u
confirmación no existe. 4 Git insiste en extraer todos los archivos de esa u
confirmación en el árbol de trabajo actual. Esto significa que los archivos no deben existir en absoluto o tener el mismo contenido que en la u
confirmación.
Para que eso suceda, puede usarlo git clean
usted mismo, pero recuerde que los archivos sin seguimiento (ignorados o no) no tienen otra existencia dentro de un repositorio Git, ¡así que asegúrese de que todos estos archivos se puedan destruir! O puede crear un directorio temporal y mover los archivos allí para su custodia, o incluso hacer otro git stash save -u
o git stash save -a
, ya que estos se ejecutarán git clean
automáticamente. Pero eso te deja con otro u
alijo de estilo con el que lidiar más tarde.
1 Esto es de hecho refs/stash
. Esto es importante si crea una rama llamada stash
: el nombre completo de la rama es refs/heads/stash
, por lo que no están en conflicto. Pero no hagas eso: a Git no le importará, pero te confundirás. :-)
2 El git stash
código realmente se usa git merge-recursive
directamente aquí. Esto es necesario por varias razones y también tiene el efecto secundario de asegurarse de que Git no lo trate como una fusión cuando resuelva conflictos y se comprometa.
3 Por eso recomiendo evitar git stash pop
, a favor de git stash apply
. Tiene la oportunidad de revisar lo que se aplicó y decidir si realmente se aplicó correctamente. Si no, todavía tienes tu alijo, lo que significa que puedes usarlo git stash branch
para recuperar todo perfectamente. Bueno, asumiendo la falta de ese molesto u
compromiso.
4 Realmente debería haber: git stash apply --skip-untracked
o algo. También debería haber una variante que signifique colocar todos esos u
archivos de confirmación en un nuevo directorio , por ejemplo git stash apply --untracked-into <dir>
, quizás.
git stash show -p | git apply --3