¿Cómo puedo recuperar el contenido de un file oculto específico después de haber extraído la nueva versión de mi proyecto GIT?

No estoy tan interesado en GIT y tengo el siguiente problema.

Tengo un file no asignado en mi proyecto que he guardado en esta statement:

git stash 

Luego, hago que el repository tome el trabajo de una coolega, que parece haber sobrescrito correctamente los cambios de mi file escondido.

Ahora quiero recuperar el contenido de un file escondido específico sin perder la modificación de mi colega.

No quiero anular la versión extraída, sino solo acceder al código de la versión almacenada de un file específico.

Al realizar la list de git stash obtengo :

 $ git stash list stash@{0}: WIP on master: fd2a59b First version of iterate/aggregate for data received from dataservice stash@{1}: WIP on master: 4910263 DSS project added 

¿Cómo puedo hacerlo desde el caparazón?

No sé si es posible mostrar fácilmente la diferencia de un file específico en un escondite.

Sin embargo, para mostrar el código oculto de stash@{0}

 git stash show stash@{0} -p 

Si no está satisfecho con la salida del command anterior, y dado que su tree de trabajo está limpio, puede comenzar obteniendo el alijo deseado

 # say you want to see diff of file my/file1.txt in stash{0} git stash pop stash@{0} # To Check your file by showing the diff between your work and your collegue's git diff my/file1.txt 

Para volver al primer paso

 git stash 

Espero que ayude

Resuelto por mí mismo:

1) Primero muestre el file escondido usando la statement del show de git stash :

 $ git stash show glis-toolkit/src/main/synapse-config/api/glisTest2.xml | 8 ++++++++ 1 file changed, 8 insertions(+) 

2) Luego guardo esta versión escondida (del alijo 0) en otro file de copy de security por:

 $ git show stash@{0}:glis-toolkit/src/main/synapse-config/api/glisTest2.xml > glisTest2Bck.xml 

Hay varias partes en esta respuesta, porque usar git stash puede ser sorprendentemente difícil. La forma en que lo usaste en este caso es correcto para tu caso de uso, pero hay muchas trampas aquí para los incautos y los nuevos en / no tan en la gente de GIT.

Stash hace varios commits

Lo principal para saber, de lo que todo lo demás fluye, es esto: git stash hace commits. De hecho, hace al less dos commits; si le dices (con -u o -a ) hace un tercer commit. Todos estos commits no están en ninguna twig, pero siguen siendo commits, y por lo tanto se comportan como commits. El formatting de estos commits es que se ven, a otros commands de Git, como un tipo extraño de commit de fusión , lo que significa en general que quieres evitar que otros commands de Git los miren demasiado, y en su mayoría usan git stash para lidiar con ellos.

El índice y el tree de trabajo, y el git checkout

Lo que git stash comete es el índice y el tree de trabajo . El tree de trabajo es el más fácil de explicar, de lejos: Git almacena files en un formatting interno, solo Git, por lo que para trabajar con los files, necesita un lugar donde se almacenan en el formatting de computadora normal. Ese es el tree de trabajo. Puede colocar, en este tree de trabajo, files que no se almacenarán también en Git, y aquí es donde entra el índice .

El índice de Git tiene varios usos, pero este es el principal: es "donde se construye el siguiente compromiso". Es decir, comienzas, en cualquier repository de Git, con un compromiso actual para ejecutar git checkout . (En el primer git clone , Git ejecuta git checkout master para ti. Bueno, generalmente es master todos modos, pero definitivamente es algo que se presta). Esto selecciona un nombre de twig, lo usa para encontrar el commit de la twig, y ​​lo hace twig y que comprometen su twig actual y comprometerse. Luego llena el índice, que estaba completamente vacío, la primera vez, de esa confirmación en particular, de modo que ahora el índice tiene todos los files que están en la confirmación actual (o HEAD ). Al agregar estos files al índice, Git también los copy en el tree de trabajo, por lo que ahora tiene el compromiso HEAD igual al índice que es igual al tree de trabajo.

Si ahora git checkout alguna otra sucursal / compromiso, Git cambia HEAD para tener en count la nueva sucursal y propina la propina, elimina los files antiguos (para la CABEZA anterior) del índice y del tree de trabajo, agrega los nuevos files al índice y tree de trabajo, y una vez más, tiene el compromiso HEAD igual al índice que es igual al tree de trabajo.

Tenga en count que en todo este reorderamiento, cualquier file que se encuentre en el tree de trabajo que no esté en el índice, permanece intacto. Estos son sus files sin seguimiento , y eso es lo que significa que un file no se rastree: se realiza un seguimiento de un file si y solo si está en el índice. (Esto solo tiene un poco que ver con el git stash , pero es crucial usar Git y .gitignore , porque .gitignore no tiene efecto en un file rastreado ).

Para hacer un nuevo commit usted mismo, primero debe modificar un file en el tree de trabajo, luego use git add para copyr la nueva versión en el índice. Esto hace que el nuevo file esté listo para comprometerse, con los datos que tiene justo en el momento en que ejecuta git add . Esto deja todos los files de índice existentes tal como están, por lo que la nueva confirmación aún conservará todos los otros files. Para agregar un file que aún no está en el índice, lo crea en el tree de trabajo y nuevamente ejecuta git add . Copia el file en el índice, al igual que antes, pero esta vez no sobrescribe una copy existente. Para eliminar un file, ejecuta git rm , que lo elimina tanto del índice como del tree de trabajo.

Este process de agregar (sobreescribir files existentes o agregar nuevos) al índice, y eliminar files de index-and-work-tree, es lo que queremos decir cuando decimos files de ensayo para commit. Esta es la razón por la cual el índice también se llama "el área de ensayo": es donde copymos los files actualizados del tree de trabajo en, para que se organicen. Tenga en count que, a less que se lo git rm todo, el índice en sí mismo nunca estará vacío en realidad : es solo que una vez que git commit el índice, el índice y el nuevo compromiso que hizo, ahora coinciden. (Esto hace que el --allow-empty to git commit un poco engañoso.)

Regrese a git stash , específicamente el sub-command "save nuevo stash"

Nuevamente, git stash save hace (al less) dos commits: primero, confirma el índice en sí mismo -lo cual es realmente fácil ya que así es como Git siempre realiza commits- y luego realiza un segundo commit que consiste, en efecto, en git add todos los files de tree de trabajo rastreados, es decir, copyrlos en el índice y luego volver a cometerlos. Por razones internas, sin embargo, hace que este segundo compromiso se comporte como una fusión , fusionando HEAD y el índice que acaba de cometer. No tenemos que preocuparnos siempre que usemos git stash para lidiar con esta combinación extraña. Es solo cuando git stash que repentinamente tenemos que preocuparnos por eso.

Después de que git stash hace esos commits, en su mayoría hace el equivalente a git reset --hard HEAD , aunque aquí también hay opciones de bandera para cambiar esto. (Por mucho, tal vez demasiado, más sobre este process, consulte Cómo recuperarse de "git stash save –all"? ) Lo que git reset --hard HEAD hace es volver a establecer (de ahí que git reset ) tres cosas:

  1. Se mueve (es decir, restablece) la twig actual de su compromiso actual a la nueva confirmación especificada. Debido a que la nueva confirmación especificada es HEAD , que es la confirmación actual, esto es como tratar de conducir desde su cocina a su cocina: puede escabullirse por un time, pero acaba exactamente donde comenzó.

  2. Re-establece el índice. Es decir, hace que el índice coincida con el compromiso HEAD . Esto desestabiliza todos los cambios efectuados, elimina los files modificados, elimina todos los files totalmente nuevos y se recupera de los files modificados y luego organizados.

  3. Re-establece el tree de trabajo. Es decir, hace que todos los files rastreados en el tree de trabajo coincidan con sus versiones en el compromiso HEAD y (ahora) el índice.

Sin embargo, como una especie de atajo mental, puedes pensar en esto como "resam out the index and work-tree". El código de stash simplemente los guardó a ambos, como confirmaciones, por lo que ahora es seguro eliminarlos. Ahora, tanto el índice como el tree de trabajo se parecen a los que tendrían si acabaran de ejecutar la ejecución de git checkout en la confirmación actual. Esta es la razón por la que ahora está listo para usar git merge o git rebase (lo ejecute o no desde git pull -remember, git pull es solo git fetch seguido de merge o rebase, en todos estos casos).

Aplicando el alijo

El process de aplicar (o "explotar") un alijo puede ser más complicado que el process de savelo, pero en la práctica , tiende a ser simple. Bueno, excepto cuando sale mal, de todos modos. Acaba de llegar a un estado (generalmente limpio) commit-and-index-and-work-tree como antes y ejecuta:

 git stash apply 

Lo que hace es ejecutar un par de commands git diff para descubrir:

  • ¿Cuál es la diferencia entre el índice guardado y la confirmación que era actual cuando git stash save guardado git stash save ese índice?
  • ¿Cuál es la diferencia entre el tree de trabajo guardado y el compromiso que estaba vigente cuando el guardado de git stash save guardó ese tree de trabajo?

Por lo general, para cada file, hay como máximo una diferencia (ya sea a través del índice guardado, o del tree de trabajo guardado): organizó el file, por lo que la diferencia aparece en el índice guardado, o no, por lo que todos los cambios que hagas aparecerán en el tree de trabajo guardado (si no hay cambios, no hay ninguna diferencia). Git luego destruye todo esto, para cada file, y pone todos los cambios en su tree de trabajo actual. Su índice actual no se ve afectado, de forma pnetworkingeterminada, aunque hay forms más sofisticadas de git stash apply .

Una vez que esté satisfecho de que el escondite se haya aplicado correctamente, puede ejecutar git stash drop . Esto descarta los dos commits guardados (y si git stash save "empujó" un alijo anterior en stash@{1} , "pops" efectivamente el rest hacia abajo para que el alijo anterior ahora esté stash@{0} , o simplemente stash ) .

Si está seguro de querer tirar el alijo después de aplicarlo, sin verificar primero si es correcto, puede usar git stash pop . Esto literalmente se convierte en git stash apply && git stash drop internamente. (Por supuesto, pasa el alijo específico, si está usando git stash pop stash@{n} .)

Algunos casos difíciles, como files XML

El process de aplicar cada cambio, cada git diff de commit-that-was-HEAD-at-the-time, al índice guardado o al tree de trabajo guardado, usa los poderes de fusión completos de Git. Este es un process mecánico simple (ish), pero funciona sorprendentemente bien para la mayoría de los files. Los files XML, desafortunadamente, tienden a derrotar a los no exactamente súper poderes de Git.

En este caso, es posible que desee hacer exactamente lo que hizo aquí.

Debido a que git stash save simplemente hace dos commits (que no están en una twig), puedes usar todas las herramientas Git habituales para lidiar con estos dos commits. Pero una vez que lo haces, debes tener cuidado, porque la confirmación del tree de trabajo parece una fusión. (Bueno, de hecho, se trata de un commit de fusión.) Afortunadamente, git show <commit>:<path> no tiene en count si el commit es una combinación: simplemente extrae la versión guardada del file.

Cada nombre de stash o nombre de reflog apunta a la confirmación guardada del tree de trabajo. Por lo tanto:

 git show stash:path/to/file.xml 

imprime los contenidos del tree de trabajo guardado de ese file. Redirigir eso a un nuevo file en su tree de trabajo le da la oportunidad de examinar los contenidos guardados. Así que esto es algo bueno de hacer.

Ten cuidado, sin embargo, para git show stash . Para aquellos de nosotros con dislexia, 1 es realmente fácil de usar en lugar de git stash show . Pero a git show <commit> le importa si <commit> es un commit de fusión. Mientras que git stash show sabe cómo tratar el commit del tree de trabajo como un commit separado, non-merge-y, git show -que ve el stash como un ID de confirmación, que luego funciona pero te da el commit del tree de trabajo para tratarlo como un compromiso de fusión Intenta mostrar una diferencia combinada , que a menudo acaba mostrando nada en absoluto. (El caso más confuso se produce cuando muestra algo, pero no todo lo que escondió, lo que sucede cuando primero organizó un file, luego lo modificó nuevamente en el tree de trabajo).

TL; resumen de DR (si no es demasiado tarde): git show stash:path/to/file está bien, pero git show stash es siempre un error. Lo que más desea es que se git stash apply , pero en casos raros, git show stash:path/to/file obtendrá la versión guardada del tree de trabajo . Y, para casos realmente complicados, vea mi otra respuesta más larga y considere usar la git stash branch .


1 Disléxicos del mundo desatar!