Tuve un montón de cambios por etapas y no por etapas y quería cambiar rápidamente a otra rama y luego volver.
Así que organicé mis cambios usando:
$ git stash push -a
(En retrospectiva, probablemente podría haber usado en --include-untracked
lugar de --all
)
Luego, cuando fui a hacer estallar el alijo, recibí una gran cantidad de errores como:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
No parece haber ningún cambio restaurado desde el alijo.
También lo intenté, $ git stash branch temp
pero eso muestra los mismos errores.
Descubrí una forma de evitar esto que debía usar:
$ git stash show -p | git apply
Desastre evitado por ahora, pero esto plantea algunas preguntas.
¿Por qué ocurrió este error en primer lugar y cómo puedo evitarlo la próxima vez?
git stash show -p | git apply --3
git stash show
y que los archivos de rescate, uno por uno:$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Esto obtendrá el archivo del alijo y lo guardará con un nombre diferente. Ahora está seguro de experimentar con los métodos de rescate adecuados (vea las respuestas a continuación). Si las cosas van por mal camino, siempre tendrá sus archivos rescatados como último recurso.Respuestas:
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 yw
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 eli
compromiso es de hecho un compromiso perfectamente normal! Simplemente no está en ninguna rama:Si está haciendo un alijo normal, el
git stash
código lo hacew
ahora copiando todos sus archivos de árbol de trabajo rastreados (en un índice auxiliar temporal). Git establece que el primer padre de estaw
confirmación apunte a laHEAD
confirmación y el segundo padre apunte a la confirmacióni
. Por último, se establecestash
para apuntar a estew
compromiso:Si agrega
--include-untracked
o--all
, Git realiza una confirmación adicionalu
, entre haceri
yw
. El contenido de la instantáneau
son aquellos archivos que no se rastrean pero no se ignoran (--include-untracked
), o archivos que no se rastrean incluso si se ignoran (--all
). Estau
confirmación adicional no tiene padre, y luego, cuando segit stash
realizaw
, establecew
el tercer padre en estau
confirmación, de modo que obtiene:Git también, en este punto, elimina los archivos del árbol de trabajo que terminaron en la
u
confirmación (usandogit clean
para hacer eso).Restaurar un alijo
Cuando vas a restaurar un alijo, tienes la opción de usarlo
--index
o no. Esto le dicegit stash apply
(o cualquiera de los comandos que usa internamenteapply
, comopop
) que debe usar eli
compromiso para intentar modificar su índice actual. Esta modificación se realiza con:(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 lai
confirmación.Si el alijo tiene solo dos confirmaciones,
git stash apply
ahora puede aplicar law
confirmación. Hace esto llamando agit 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 yw
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 lagit stash apply
misma tiene éxito. Si solíagit 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 paragit 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 lau
confirmación no existe. 4 Git insiste en extraer todos los archivos de esau
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 lau
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 otrogit stash save -u
ogit stash save -a
, ya que estos se ejecutarángit clean
automáticamente. Pero eso te deja con otrou
alijo de estilo con el que lidiar más tarde.1 Esto es de hecho
refs/stash
. Esto es importante si crea una rama llamadastash
: el nombre completo de la rama esrefs/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 usagit 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 degit 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 usarlogit stash branch
para recuperar todo perfectamente. Bueno, asumiendo la falta de ese molestou
compromiso.4 Realmente debería haber:
git stash apply --skip-untracked
o algo. También debería haber una variante que signifique colocar todos esosu
archivos de confirmación en un nuevo directorio , por ejemplogit stash apply --untracked-into <dir>
, quizás.fuente
--index
:git stash apply --index
?git stash save --all
, luego lo hice de inmediatogit stash apply
, pero faltaban algunos archivos porque les cambié el nombre y luego los volví a crear (antes de guardarlos). Lo que ayudó fue:git checkout stash@{0} -- .
ni siquiera me molestarégit checkout stash^3 -- .
porque todo parece estar bien ahora. Es una pena que no tenga tiempo para entender realmente lo que estaba pasando. Gracias.Me las arreglé para recrear tu problema. Parece que si oculta los archivos sin seguimiento y luego crea esos archivos (en su ejemplo,
foo.txt
ybar.txt
), entonces tiene cambios locales en los archivos sin seguimiento que se sobrescribirán cuando realice la solicitudgit stash pop
.Para solucionar este problema, puede utilizar el siguiente comando. Esto anulará cualquier cambio local no guardado, así que tenga cuidado.
Aquí hay más información que encontré en el comando anterior .
fuente
--all
/-a
incluirá archivos ignorados , por lo que puede ser relevante.git merge --squash --strategy-option=theirs stash
enfoque es mejor en este caso).already exists, no checkout
), verifique mi respuesta a continuación.Para ampliar la respuesta de Daniel Smith : ese código solo restaura los archivos rastreados , incluso si usó
--include-untracked
(o-u
) al crear el alijo. El código completo requerido es:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
Esto restaura completamente el contenido rastreado (en
stash
) y el contenido no rastreado (enstash^3
), luego elimina el alijo. Algunas notas:git checkout
hace que todos se conviertan en etapas automáticamente, por lo que he agregadogit reset
para quitar la etapa de todo.stash@{0}
ystash@{0}^3
, en mis pruebas, funciona igual con o sin@{0}
Fuentes:
stash^3
compromiso mágico )fuente
Aparte de otras respuestas, hice un pequeño truco
git stash apply
(puede usar cualquier comando, por ejemplo, aplicar, hacer estallar, etc.)fuente