git esconder y aplicar

Soy nuevo en git y no tengo muy claro cómo funciona el almacenamiento.

Digamos que estoy trabajando en Branch Master y trato de git pull y recibir el error de que mis cambios locales se sobrescriban y de que tengan que ocultarse o comprometerse. Si no he organizado ninguno de mis cambios y ejecuto git stash , entonces hago un git pull y lo actualizo con éxito, ¿qué sucede cuando git stash apply ?

En general, si alguien más modifica los files y ejecuto git pull , ¿qué sucede cuando run git stash apply ? ¿sobrescribe los files que se acaban de actualizar, independientemente de si se realizaron o no cuando los escondí? ¿Sobrescribe todos los files que acabo de actualizar con git pull , con los files que estaban escondidos?

Versión rápida para llevar "TL; DR", para que uno pueda volver más tarde y estudiar más

git stash cuelga un alijo-esta es una forma peculiar de un commit de fusión que no está en ninguna twig-en el commit HEAD actual. Se git stash apply posterior, cuando estás en un commit, probablemente un commit diferente , luego intentas restaurar los cambios que git calcula al mirar el stash-bag colgante y el commit desde el que cuelga.

Cuando hayas terminado con los cambios, debes usar git stash drop para soltar el alijo del commit que fue "escondido". (Y, git stash pop es solo una abreviatura para "aplicar, luego soltar automáticamente". Recomiendo mantener los dos pasos separados, sin embargo, en caso de que no te guste el resultado de "aplicar" y quieras volver a intentarlo más tarde).

La versión larga

git stash es realmente bastante complejo.

Se ha dicho que "git tiene mucho más sentido una vez que entiendes X" , para muchos valores diferentes de "X", que se generaliza a "git tiene mucho más sentido una vez que entiendes git". 🙂

En este caso, para comprender realmente el stash , necesita comprender cómo se comprometen, twigs, el área de índice / etapas, el espacio de nombres de reference de git y fusiona todo el trabajo, porque git stash crea un compromiso de fusión muy peculiar al que hace reference un nombre fuera de los espacios de nombre habituales -un tipo extraño de combinación que no está "en una twig" en absoluto- y git stash apply utiliza la maquinaria de fusión de git para intentar "volver a aplicar" los cambios guardados cuando se cometió la peculiar fusión hecho, preservando opcionalmente la distinción entre cambios por etapas y cambios por etapas.

Afortunadamente , no es necesario que entiendas todo eso para usar git stash .

Aquí, estás trabajando en alguna twig ( master ) y tienes algunos cambios que aún no están listos, por lo que no quieres comprometerlos en la twig. 1 Mientras tanto, otra persona pone algo bueno, o al less, espera que sea bueno, en el origin/master en el repository remoto, por lo que desea recogerlos.

Digamos que usted y los dos comenzaron con commits que terminan en - A - B - C , es decir, C es la confirmación final que usted tuvo en su repository cuando comenzó a trabajar en Branch master . El nuevo "algo bueno" se compromete, llamaremos D y E

En su caso, está ejecutando git pull y falla con el problema "el directory de trabajo no está limpio". Entonces, ejecutas git stash . Esto compromete tus cosas para ti, en su especial y extraño estilo stash-y, para que tu directory de trabajo esté ahora limpio. Ahora puedes git pull .

En términos de dibujo de confirmaciones (un gráfico como el que obtienes con gitk o git log --graph ), ahora tienes algo como esto. El alijo es la pequeña bolsa de iw cuelga de la confirmación que estaba "en", en su twig master , cuando ejecutó git stash . (La razón de los nombres i y w es que estas son las partes "i" ndex / staging-area y "w" ork-tree del stash).

 - A - B - C - D - E <-- HEAD=master, origin/master |\ iw <-- the "stash" 

Este dibujo es lo que obtienes si comenzaste a trabajar en master y nunca hiciste ningún commit. El commit más reciente que tuviste fue por lo tanto C Después de hacer el alijo, git pull pudo agregar commits D y E a su branch master local. La bolsa de trabajo escondida sigue colgando C

Si ha realizado algunos commits propios, los llamaremos Y , para su confirmación, y Z solo para tener dos commits, el resultado de "stash then pull" se ve así:

  .-------- origin/master - A - B - C - D - E - M <-- HEAD=master \ / Y - Z |\ iw <-- the "stash" 

Esta vez, después de que stash colgara su bolsa de Z , el pull -que es solo fetch luego merge que fusionarse realmente, en lugar de solo un "avance rápido". Entonces hace commit M , la fusión se compromete. La label de origin/master todavía se refiere a confirmar E , no M Ahora estás en master en commit M , que es una fusión de E y Z Eres "uno por delante" de origin/master .

En cualquier caso, si ahora ejecuta git stash apply , el script stash (es un script de shell que usa una gran cantidad de commands de "fontanería" de bajo nivel) de manera efectiva 2 hace esto:

 git diff stash^ stash > /tmp/patch git apply /tmp/patch 

Esto diffs stash , que nombres w el "tree de trabajo" parte del escondite-contra el padre correcto 3 . En otras palabras, descubre "lo que ha cambiado" entre la confirmación padre adecuada ( C o Z , según corresponda) y el tree de trabajo oculto. A continuación, aplica los cambios a la versión actualmente desprotegida, que es E o M , nuevamente según dónde comenzó.

Por cierto, git stash show -p realmente solo ejecuta el mismo command git diff (sin parte de > /tmp/patch ). Sin -p , ejecuta el diff con --stat . Entonces, si quieres ver en detalle qué se git stash apply , utiliza git stash show -p . (Sin embargo, esto no le mostrará qué puede git stash apply para intentar aplicar desde la parte del índice del alijo, esta es una queja menor que tengo con el script de alijo).


En cualquier caso, una vez que el alijo se aplica limpiamente, puede usar git stash drop para eliminar la reference al alijo, para que pueda ser recogido. Hasta que lo dejes caer, tiene un nombre ( refs/stash , también conocido como stash@{0} ) por lo que se queda "para siempre" … excepto por el hecho de que si creas un nuevo alijo, el script de stash "empuja" el el alijo actual en el reflog de ocultación (para que su nombre se convierta en stash@{1} ) y hace que el nuevo alijo use el nombre de refs/stash . La mayoría de las inputs de reflog se mantienen durante 90 días (puede configurar que esto sea diferente) y luego caducan. Los espacios publicitarios no caducan de manera pnetworkingeterminada, pero si lo configuras de otra manera, un alijo "empujado" puede perderse, así que ten cuidado con depender de "save para siempre" si comienzas a configurar git a tu gusto.

Tenga en count que git stash drop "pops" aquí, stash@{2} numerar stash@{2} para stash@{1} y haciendo que stash@{1} convierta en simple stash . Usa la git stash list para ver el stash-stack.


1 No está mal seguir adelante y comprometerlos de todos modos, y luego hacer una posterior git rebase -i para aplastar o corregir más segundo, tercero, cuarto, …, n-ésimo commit y / o reescribir el compromiso de "punto de control" temporal. Pero eso es independiente de esto.

2 Es un poco más complejo porque puedes usar --index para tratar de mantener los cambios escalonados por etapas, pero de hecho, si miras en el script, verás la secuencia de commands actual git diff ... | git apply --index git diff ... | git apply --index . ¡Realmente solo aplica una diferencia, en este caso! Finalmente, invoca git merge-recursive directamente, para fusionarse en el tree de trabajo, permitiendo que los mismos cambios hayan sido introducidos desde otro lugar. Una git apply simple de git apply fallaría si tu parche hace algo que "lo bueno" compromete D y E también lo hace.

3 Esto usa la syntax mágica de nombres de padres de git, con un poco de planificación anticipada dentro del script stash . Debido a que el alijo es este funky merge commit, w tiene dos o incluso tres padres, pero el script stash lo configura para que el "primer padre" sea el commit original, C o Z , según corresponda. El stash^2 "segundo padre" stash^2 es el estado del índice en el momento de la confirmación, que se muestra como i en el pequeño alijo colgante, y el "tercer padre", si existe, es files sin escena y tal vez ignorados , de git stash save -u o git stash save -a .

Tenga en count que asumo, en esta respuesta, que no ha organizado cuidadosamente parte de su tree de trabajo y que no está usando git stash apply --index para restaurar el índice por etapas. Al no hacer nada de esto, haces que el compromiso sea bastante networkingundante, por lo que no tenemos que preocuparnos por ello durante el paso de apply . Si está utilizando apply --index o equivalente, y tiene elementos por etapas, puede acceder a muchos más casos de esquina, donde el alijo no se aplicará limpiamente.

Estas mismas advertencias se aplican, con aún más casos de esquina, a los depósitos guardados con -u o -a , que tienen ese tercer compromiso.

Para estos casos extra duros, git stash proporciona una forma de convertir un alijo en una twig completa , pero dejaré todo eso en otra respuesta.

Generalmente los cambios no comprometidos son siempre malos. O bien tus cambios son buenos, luego los comprometes, o son malos que los descartes. Hacer cualquier operación de git mientras tiene cambios no comprometidos tiende a causar problemas y git no podrá ayudarlo, ya que git no sabe nada de lo que no haya cometido.

Habiendo dicho eso, regrese a su pregunta. 😉

Git es generalmente bastante inteligente. Cuando aplica su escondite, intenta combinar sus cambios con los otros cambios. La mayoría de las veces esto solo funciona.

Si los cambios realmente entran en conflicto, porque cambiaste las mismas líneas de una manera diferente, Git te lo dirá, y tendrás que resolver el conflicto tú solo. – Incluso en este caso, Git te ayudará con git mergetool , que lanzará un command adecuado para mostrarte los conflictos y te permite resolverlos uno por uno.

el command stash git restring de dónde viene el alijo:

  git stash list 

fuera puesto

  stash@{0}: WIP on master.color-rules.0: 35669fb [NEW] another step toward initial cube 

Donde puedes ver en que SHA1 fue hecho. Así que, si se equivoca, Git Pull, Git Sshsh se aplica y tiene un conflicto, el alijo no se descarta (solo si se cae o si la aplicación fue exitosa). Así que siempre puedes get SHA1 de la list de git stash y

  git checkout 35669fb git stash apply 

y está garantizado para trabajar. Recomiendo usar la opción -b y proporcionar un nombre de twig para esa recuperación.

Habiendo dicho eso, mi flujo de trabajo favorito es SIEMPRE pagar con un nuevo nombre "personal" para evitar tales problemas