¿Cómo puedo extraer un solo archivo (o cambios en un archivo) de un alijo de git?
¿Es posible extraer un solo archivo o una diferencia de un archivo de un alijo de git sin desactivar el conjunto de cambios del alijo?
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:
Un alijo 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ó el alijo.
Por lo tanto, puede tratar el alijo (por ejemplo stash@{0}
, es el primer alijo/el más alto) como una confirmación de fusión y usar:
$ git diff stash@{0}^1 stash@{0} -- <filename>
Explicación: stash@{0}^1
significa el primer padre del alijo dado, que, como se indica en la explicación anterior, es la confirmación en la que se guardaron los cambios. Usamos esta forma de "git diff" (con dos confirmaciones) porque stash@{0}
/ refs/stash
es una confirmación de fusión y tenemos que decirle a git con qué padre queremos comparar. 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 derev^!
la sintaxis, en la sección "Especificar rangos").
Del mismo modo, puedes usar git checkout para retirar un solo archivo del alijo:
$ 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 la ruta completa de un archivo en relación con el directorio superior de un proyecto (piense: en relación con stash@{0}
)).
Es posible que necesites protegerte stash@{0}
de la expansión del shell, es decir, usar "stash@{0}"
o 'stash@{0}'
.
Si usa git stash apply
en lugar de git stash pop
, aplicará el alijo a su árbol de trabajo pero aún lo conservará.
Una vez hecho esto, puede add
/ commit
el archivo que desee y luego restablecer los cambios restantes.
$ git checkout stash@{0} -- <filename>
Notas:
Asegúrese de poner espacio después de "--" y el parámetro de nombre de archivo
Reemplace cero (0) con su número de alijo específico. Para obtener la lista de alijo, utilice:
git stash list
Basado en la respuesta de Jakub Narębski - Versión más corta
Editar: vea la respuesta de cambunctious , que es básicamente lo que prefiero ahora porque solo usa los cambios en el alijo, en lugar de compararlos con su estado actual. Esto hace que la operación sea aditiva, con muchas menos posibilidades de deshacer el trabajo realizado desde que se creó el alijo.
Para hacerlo de forma interactiva, primero harías
git diff stash^! -- path/to/relevant/file/in/stash.ext perhaps/another/file.ext > my.patch
... luego abra el archivo de parche en un editor de texto, modifíquelo según sea necesario y luego haga
git apply < my.patch
La respuesta de cambunctious evita la interactividad al conectar un comando directamente al otro, lo cual está bien si sabes que quieres todos los cambios del alijo. Puede editarlo stash^!
para que sea cualquier rango de confirmación que tenga los cambios acumulativos que desee (pero primero verifique el resultado de la diferencia).
Si falla la aplicación del parche/diff, puede cambiar el último comando al git apply --reject
que realiza todos los cambios que puede y deja .rej
archivos donde hay conflictos que no puede resolver. Luego, los .rej
archivos se pueden aplicar usando wiggle
, así:
wiggle --replace path/to/relevant/file/in/stash.ext{,.rej}
Esto resolverá el conflicto o le dará marcadores de conflicto que obtendría de una fusión.
Si tu distribución no lo tiene wiggle
, puedes simplemente compilarlo:
cd /usr/local/src/
git clone git://git.neil.brown.name/wiggle
cd wiggle/
git checkout v1.3
make install
Solución anterior: existe una forma sencilla de obtener cambios de cualquier rama, incluidos los alijos:
$ git checkout --patch stash@{0} path/to/file
Puede omitir la especificación del archivo si desea aplicar parches en muchas partes. U omita el parche (pero no la ruta) para obtener todos los cambios en un solo archivo. Reemplácelo 0
con el número de alijo de git stash list
, si tiene más de uno. Tenga en cuenta que esto es como diff
y ofrece aplicar todas las diferencias entre las ramas. Para obtener cambios de una sola confirmación/alijo, eche un vistazo a git cherry-pick --no-commit
.
Respuesta corta
Para ver el archivo completo:git show stash@{0}:<filename>
Para ver la diferencia:git diff stash@{0}^1 stash@{0} -- <filename>