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-untrackedlugar 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 temppero 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 --3git stash showy 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 stashhace dos confirmaciones o tres confirmaciones. El valor predeterminado es dos; obtienes tres si usas cualquier ortografía de las opciones--allo--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
ipara el contenido del índice / área de ensayo ywpara 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 elicompromiso es de hecho un compromiso perfectamente normal! Simplemente no está en ninguna rama:Si está haciendo un alijo normal, el
git stashcódigo lo hacewahora copiando todos sus archivos de árbol de trabajo rastreados (en un índice auxiliar temporal). Git establece que el primer padre de estawconfirmación apunte a laHEADconfirmación y el segundo padre apunte a la confirmacióni. Por último, se establecestashpara apuntar a estewcompromiso:Si agrega
--include-untrackedo--all, Git realiza una confirmación adicionalu, entre haceriyw. El contenido de la instantáneauson aquellos archivos que no se rastrean pero no se ignoran (--include-untracked), o archivos que no se rastrean incluso si se ignoran (--all). Estauconfirmación adicional no tiene padre, y luego, cuando segit stashrealizaw, establecewel tercer padre en estauconfirmación, de modo que obtiene:Git también, en este punto, elimina los archivos del árbol de trabajo que terminaron en la
uconfirmación (usandogit cleanpara hacer eso).Restaurar un alijo
Cuando vas a restaurar un alijo, tienes la opción de usarlo
--indexo no. Esto le dicegit stash apply(o cualquiera de los comandos que usa internamenteapply, comopop) que debe usar elicompromiso 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 applyignora por completo laiconfirmación.Si el alijo tiene solo dos confirmaciones,
git stash applyahora puede aplicar lawconfirmación. Hace esto llamando agit merge2 (sin permitirle confirmar o tratar el resultado como una fusión normal), usando la confirmación original en la que se hizo el alijo (iel padre ywel primer padre) como base de fusión,wcomo el--theirscommit, 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 applymisma tiene éxito. Si solíagit stash popaplicar 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
uconfirmación en el alijo que está aplicando, ¡entonces las cosas cambian! No hay opción para fingir que lauconfirmación no existe. 4 Git insiste en extraer todos los archivos de esauconfirmación en el árbol de trabajo actual. Esto significa que los archivos no deben existir en absoluto o tener el mismo contenido que en lauconfirmación.Para que eso suceda, puede usarlo
git cleanusted 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 -uogit stash save -a, ya que estos se ejecutarángit cleanautomáticamente. Pero eso te deja con otroualijo 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 stashcódigo realmente se usagit merge-recursivedirectamente 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 branchpara recuperar todo perfectamente. Bueno, asumiendo la falta de ese molestoucompromiso.4 Realmente debería haber:
git stash apply --skip-untrackedo algo. También debería haber una variante que signifique colocar todos esosuarchivos 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.txtybar.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/-aincluirá archivos ignorados , por lo que puede ser relevante.git merge --squash --strategy-option=theirs stashenfoque 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 resetEsto restaura completamente el contenido rastreado (en
stash) y el contenido no rastreado (enstash^3), luego elimina el alijo. Algunas notas:git checkouthace que todos se conviertan en etapas automáticamente, por lo que he agregadogit resetpara quitar la etapa de todo.stash@{0}ystash@{0}^3, en mis pruebas, funciona igual con o sin@{0}Fuentes:
stash^3compromiso 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