¿Cómo extraería un solo archivo (o cambios a un archivo) de un git stash?

776

Me gustaría saber si es posible extraer un solo archivo o diff de un archivo de un escondite de git sin hacer estallar el conjunto de cambios de escondite.

¿Alguien podría proporcionar algunas sugerencias / ideas sobre esto?

Danny
fuente

Respuestas:

1132

En la página de manual de git stash puedes leer (en la sección "Discusión", justo después de la descripción de "Opciones") que:

Una reserva se representa como una confirmación cuyo árbol registra el estado del directorio de trabajo, y su primer padre es la confirmación en HEAD cuando se creó la reserva.

Por lo tanto, puede tratar el alijo (por ejemplo, el alijo stash@{0}primero / superior) como una confirmación de fusión y usar:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Explicación: stash@{0}^1significa el primer padre del alijo dado, que como se indica en la explicación anterior es el compromiso en el que se guardaron los cambios. Utilizamos esta forma de "git diff" (con dos commits) porque stash@{0}/ refs/stashes un commit de fusión, y tenemos que decirle a git contra qué padre queremos diferenciarnos. Más críptico:

$ git diff stash@{0}^! -- <filename>

también debería funcionar (consulte la página de manual de git rev-parse para obtener una explicación de la rev^!sintaxis, en la sección "Especificar rangos").

Del mismo modo, puede usar git checkout para verificar un solo archivo fuera del escondite:

$ git checkout stash@{0} -- <filename>

o para guardarlo con otro nombre de archivo:

$ git show stash@{0}:<full filename>  >  <newfile>

o

$ git show stash@{0}:./<relative filename> > <newfile>

( tenga en cuenta que aquí <nombre de archivo completo> es el nombre de ruta completo de un archivo relativo al directorio superior de un proyecto (piense: relativo a stash@{0})).


Es posible que deba protegerse stash@{0}de la expansión de shell, es decir, usar "stash@{0}"o 'stash@{0}'.

Jakub Narębski
fuente
8
Esto es bastante bueno ... Realmente no entendí cómo funcionaba el alijo hasta que leí tu respuesta (lo que me llevó a la adición de git-checkout). Realmente no entendí eso, cuando haces un alijo, git guarda DOS confirmaciones: una para el estado del índice y otra para el estado de la copia de trabajo, que es una fusión entre el índice y el HEAD original. Esto explica los árboles extraños que he visto cuando visualizo el repositorio con "gitk --all" cuando hay escondites.
Pat Notz
44
Principalmente, encuentro que la aplicación de pago git es la mejor manera de lograr lo que quería hacer. Sin embargo, tenía curiosidad y revisé git checkoutla página del manual. No puede colocar el archivo en otra ubicación. Hay una referencia a esto en: stackoverflow.com/questions/888414/…
Danny
84
$ git checkout stash @ {0} - <nombre de archivo> es muy útil, gracias
gravitación
43
Tenga en cuenta que el git checkoutenfoque copia el archivo exacto del alijo, no lo combina con lo que está en su directorio de trabajo como lo git stash applyharía. (Entonces, si tiene algún cambio desde la base en la que se creó el alijo, se perderán).
peterflynn 05 de
44
Tenga en cuenta que para git stash applypoder fusionar los cambios en un archivo que se ha modificado en el árbol de trabajo desde que se guardó el archivo, ese archivo en el árbol de trabajo debe estar organizado. Para que la fusión automática funcione, los mismos archivos no se pueden modificar tanto en la copia de trabajo como en la copia oculta para fusionar. Finalmente, la aplicación de alijo no elimina el elemento del alijo como lo git stash popharía.
Ville
46

Si usa en git stash applylugar de git stash pop, aplicará el alijo a su árbol de trabajo, pero aún lo mantendrá.

Una vez hecho esto, puede add/ commitel archivo que desee y luego restablecer los cambios restantes.

Tim Henigan
fuente
2
Hacer estallar un alijo específica: git stash pop stash@{0}(lista de los cambios escondidos: git stash list)
MrYoshiji
Si otros archivos en el escondite causan un conflicto de fusión, git no me deja comprometerme en el archivo que quiero :(
Cambunctious
33

Hay una manera fácil de obtener cambios desde cualquier rama, incluidas las reservas:

$ git checkout --patch stash@{0} path/to/file

Puede omitir la especificación del archivo si desea parchear en muchas partes. O bien, omita el parche (pero no la ruta) para obtener todos los cambios en un solo archivo. Reemplace 0con el número de alijo de git stash list, si tiene más de uno. Tenga en cuenta que esto es así diff, y ofrece aplicar todas las diferencias entre las ramas. Para obtener cambios de un solo commit / stash, échale un vistazo git cherry-pick --no-commit.

Walf
fuente
¿Esto copia el archivo exacto del alijo o se fusiona? En caso de copia, si tiene algún cambio desde que se creó el alijo, se perderán.
Danijel
2
@Danijel Read git help checkout. --patchhace una fusión interactiva, aplica cualquier trozo que apruebe en el shell (o lo que guarde si elige dejar eel parche). La ruta sola sobrescribirá el archivo, como escribí, "todos los cambios".
Walf
1
ligera mejora: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' luego git applydiffat stash@{4}solo se utilizan archivos que cambiaron entre el alijo y su padre.
Mark
25

Respuesta corta

Para ver el archivo completo: git show stash@{0}:<filename>

Para ver la diferencia: git diff stash@{0}^1 stash@{0} -- <filename>

Luboš Turek
fuente
1
No creo que le preocupara ver el alijo de un archivo en particular, solo abrir ese archivo.
Amalgovinus
1
Esto es lo que estaba buscando. Luego puede reemplazar diffcon difftoolpara usar su diferencial externo favorito.
Peet Brits
19
$ git checkout stash@{0} -- <filename>

Notas:

  1. Asegúrese de poner espacio después de "-" y el parámetro de nombre de archivo

  2. Reemplace cero (0) con su número de alijo específico. Para obtener una lista oculta, use:

    git stash list
    

Basado en la respuesta de Jakub Narębski - Versión más corta

RAM
fuente
11

Puede obtener la diferencia para un alijo con " git show stash@{0}" (o cualquiera que sea el número del alijo; vea "lista de alijo git"). Es fácil extraer la sección de la diferencia para un solo archivo.

Nathan Kitchen
fuente
2
Aún más simple para las mentes como yo: se usa git show stashpara mostrar el escondite más alto (normalmente el único que tienes). Del mismo modo, puede mostrar la diferencia entre su rama actual y el alijo con git diff head stash.
Dizzley
5

El concepto más simple de entender, aunque tal vez no sea el mejor, es que tiene tres archivos modificados y desea guardar un archivo.

Si lo hace git stashpara esconderlos a todos, git stash applypara recuperarlos nuevamente y luego git checkout f.cen el archivo en cuestión para restablecerlo de manera efectiva.

Cuando desee deshacer la ejecución de ese archivo, ejecute a git reset --hardy luego git stash applyvuelva a ejecutar , aprovechando el hecho de que git stash applyno borra la diferencia de la pila de almacenamiento.

Philluminati
fuente
1

Si los archivos escondidos necesitan fusionarse con la versión actual, use las formas anteriores usando diff. De lo contrario, puede usar git poppara desapilarlos, git add fileWantToKeeppara organizar su archivo y hacer un git stash save --keep-index, para guardar todo excepto lo que está en el escenario. Recuerde que la diferencia de esta manera con las anteriores es que "saca" el archivo del alijo. Las respuestas anteriores lo mantienen de git checkout stash@{0} -- <filename>acuerdo con sus necesidades.

Hola Soy Edu Feliz Navidad
fuente
0

Use lo siguiente para aplicar los cambios a un archivo en un alijo a su árbol de trabajo.

git diff stash^! -- <filename> | git apply

Esto generalmente es mejor que usarlo git checkoutporque no perderá ningún cambio que haya realizado en el archivo desde que creó el alijo.

rebelde
fuente