stash git temporary

stash - ¿Cuál es la mejor manera de tener un commit "temporal" en git?



git stash (7)

Digamos que tengo un proyecto con dos ramas maestro y dev. Tengo un montón de confirmaciones en dev para un evento especial que una vez probado se fusionan en maestro. Luego, una vez finalizado el evento, quiero eliminar el código específico del evento. Sin embargo, un restablecimiento de git no funcionará, ya que se han realizado otras confirmaciones desde que se agregó el código del evento.

Actualmente utilizo git checkout para desproteger los archivos anteriores a la fusión del evento y luego uso git diff para volver a agregar los cambios que se han realizado desde que se confirmó el evento. Esto me parece un método muy desordenado.

¿Alguien tiene una mejor solución para tener un código temporal en un proyecto?

Edición: Para que queden claros, los cambios deben confirmarse, presionarse, no confirmarse, presionarse.


"Código temporal"? En git usamos ramas para eso. Las confirmaciones son muy ligeras en git, y las ramas, al ser solo nombres (o referencias) para confirmaciones con un poco de lógica adjunta, son super ligeras en comparación con otros sistemas.

Lo mínimo de la lógica es que la referencia se actualiza automáticamente a la última confirmación. Eso es prácticamente todo lo que es una rama. Eso significa que crear y destruir sucursales en git es rápido, simple e incluso seguro, ya que nada se crea ni se elimina realmente. Después de una eliminación, aún puede hacer referencia al encabezado de la rama por ID de compromiso (sí, sigue ahí hasta que se recolecta basura e incluso eso sucede solo si no hay otra referencia).

Casi todos los comandos en git toman referencias a un commit como parámetros. Eso es cierto también para git merge. No estás fusionando ramas, estás fusionando compromisos. Sí, escribe ''git merge'', pero de nuevo, una rama es solo un nombre para un commit. Nada más que eso. Y dado que todo lo que necesita es agrupar los compromisos para el evento, simplemente deles un nombre.

Así que lo correcto es crear una rama para el evento. O posiblemente, dos: ''event-master'' y ''event-dev''. Ahora, desarrollas código para el evento en ''event-dev''. En caso de que encuentre un error que deba solucionarse en el código principal, esconda y cambie a su rama ''dev'' normal, codifique la corrección y confirme. Cambia de nuevo a ''evento-dev'', fusiona desde ''dev'' y abre el alijo. Seguir desarrollando, una vez hecho, cometer y probar. Si está bien, fusione ''event-dev'' en ''event-master''. Esto contendría también la solución. Tenga en cuenta que la corrección no está en "maestro" todavía.

Si necesita que la solución se fusione en ''maestro'', simplemente hágalo de la forma habitual, ya que la solución está en ''dev''.

Básicamente en esta configuración puedes:

  • Desarrolle el código principal como de costumbre: se compromete a ''dev'', prueba y fusiona en ''master'';

  • desarrolle el código específico del evento de una manera similar: se compromete a ''event-dev'', prueba y fusiona en ''event-master''; es el mismo flujo de trabajo;

  • mezclar los dos flujos de trabajo; cometer y cambiar de rama, o usar git stash;

  • fusionar ramas (casi) libremente; puede fusionar ''master'' en ''event-dev'', si master se actualiza de alguna manera y necesita los cambios para el evento; puede fusionar ''dev'' en ''event-dev'', si necesita desesperadamente los cambios para el evento y no puede esperar al ciclo de prueba habitual que los empuja a ''master''. git haría esto en la medida en que las fusiones estén limpias, es decir, a menos que haya cambiado la misma pieza de código de dos maneras diferentes en las dos ramas de desarrollo (este es un caso especial que debe manejarse);

Si necesita flexibilidad adicional, cree más sucursales. Para una súper flexibilidad, puede elegir los compromisos individuales en una rama, pero en general no lo recomiendo (hágalo solo si realmente sabe lo que está haciendo).

Finalmente, debo señalar que este flujo de trabajo es tan natural en git. En realidad, desarrollarse en ''dev'' y atraer cambios en ''master'' no es lo mejor en términos generales. Es habitual crear una rama dev para cada característica o módulo que estés desarrollando, y fusionar esas ramas en ''dev''.

Creo que la mentalidad correcta al usar git es: "¿Cómo me siento con la idea de codificar hoy? Característica X. Bien, creemos la rama ''feature-x'' y comencemos a hackear". Ese evento tuyo no es diferente.

Ahora, sé que lo que te estoy diciendo es cómo deberías haber hecho las cosas desde el principio, y eso no ayuda mucho ahora. Debe arreglar su árbol, ya que, según parece, tiene los cambios para el evento mezclados con los cambios normales en su rama ''dev''. Entonces, su problema es cómo crear correctamente ''evento-dev'' con solo los cambios para el evento y eliminarlos de ''dev'' al mismo tiempo.

Es hora de reescribir la historia. Cuán difícil será eso, depende de la naturaleza de los cambios. Por ejemplo, si todos los cambios pertenecen a un solo directorio, las cosas pueden ser más fáciles.

Esto es lo que haría (no sabiendo mejor):

  • Examine la historia con git log;

  • encuentre el compromiso correcto antes del primer cambio específico del evento, tome nota de su ID de compromiso: este es el compromiso ''día-0'';

  • crear una rama llamada ''newdev'' apuntando a ese commit. Haga esto en un árbol limpio, que es cometer antes de hacer esto: git checkout <commit-id> -b newdev;

  • crear ''evento-dev'': git checkout -b evento-dev;

  • ahora tienes dos ramas que apuntan al compromiso ''día-0'';

  • Ahora mire el historial nuevamente (git log dev), necesita seguirlo confirmando;

  • Supongo que cada confirmación que sigue al "día 0" es una confirmación que pertenece al código principal, o una que pertenece solo al evento. Lo que tienes que hacer es seleccionarlos en la rama correcta, ''newdev'' si es el código principal, ''event-dev'' si es el código de evento; hazlo una vez, en el orden correcto (desde ''día-0'' hasta hoy);

  • Si tienes mucha suerte, ningún commit que termine en ''newdev'' depende de los commit en ''event-dev'' y viceversa; estas un poco hecho es posible que desee cambiar el nombre (mantenerlos alrededor) del maestro actual y del desarrollo a maestro antiguo y antiguo, luego cambiar el nombre de nuevodev a dev, crear maestro desde dev, event-master desde event-dev y listo;

  • si tiene un poco menos de suerte, a veces tendrá que combinar ''newdev'' en ''event-dev'', porque algunas confirmaciones dependen de los cambios realizados en el código principal, lo cual está bien, aunque; si te sientes atrevido aquí, es hora de leer sobre git rebase; pero rebase no a menos que tenga que hacerlo;

  • o (peor) algunas confirmaciones en ''newdev'' dependen de los cambios en ''event-dev'' ... Vaya, ese código específico del evento no es tan específico del evento, si la rama principal lo necesita. Se requiere alguna fusión;

  • o (mal) un compromiso contiene ambos tipos de cambios: dividir y conquistar (debe separar los cambios y aplicarlos a la rama derecha), eso significa que está dividiendo el compromiso en dos;

  • o algo más que no puedo imaginar ahora porque no tengo suficientes detalles acerca de su árbol.

Podría ser una brisa o una pesadilla. Inspeccione cada confirmación de antemano (git show, puede verlo como un parche), decida qué hacer (eventualmente no elija, solo editar los archivos puede ser más fácil), si no está seguro, adivine qué, cree una rama , trabaje allí, vea qué sucede, combínelo si está contento, déjelo de otra manera e intente nuevamente.

No lo he mencionado hasta ahora, pero por supuesto puede hacer una copia de todo el árbol, incluidos los archivos git, y trabajar en la copia para que sea 100% seguro.

Hacerlo desde el principio es bastante fácil. Reparándolo ahora, bueno, buena suerte. :)


Creo que el stash hace lo que tú quieres.


En mi experiencia, algunos eventos especiales tienen una forma de recurrir. Por lo tanto, una solución alternativa a considerar aquí es crear una opción de configuración para permitir el manejo del evento especial, de modo que se pueda activar y desactivar cuando sea necesario.


Enrolle sus compromisos siguiendo mi método no patentado:

# work on a new branch git checkout -b event-36 git commit -a -m "all broken dammit" git commit -a -m "fixed that damn code" git commit -a -m "almost ready, going to eat lunch" git commit -a -m "It''s done!" # other people might be working on master in the meantime, so git checkout master git checkout -b erasemeImmediately git merge event-36 git reset --soft master # THE KEY TO THE WHOLE THING: SOFT RESET! git commit -a -m "Event 36, all code in one commit" git checkout master git merge erasemeImmediately

Puede hacer esto con reflog , pero luego necesitará un título de CS reciente (es decir, es difícil de entender).

Ahora tu cometido es uno solo. Ahora puedes usar revertir o hacer un picking en tu camino hacia una rama sin ella.


Tome el control y cree una rama: git checkout -b special-event , realice / aplique sus cambios. Una vez que finaliza el evento, simplemente vuelva a maestro y abandone / borre la rama.

Para continuar haciendo cambios, conviértalos en master y fusionelos en la rama especial a medida que avanza. git checkout master ... hace cambios ... git checkout special-event; git merge master git checkout special-event; git merge master .

Alternativamente, realice todos los cambios relacionados con eventos especiales en un compromiso, luego use git revert cuando quiera desplegarlos y especifique solo ese compromiso.


git revertir

Se eliminará cualquier confirmación o rango de confirmaciones que necesite deshacer. También es seguro empujar a un repositorio público.


git checkout -b event

... hacer un cambio de evento específico ...

git commit -am "specific event change"

... hacer otro cambio de evento específico ...

git commit -am "another specific event change"

En este punto, la rama maestra aún está intacta y los cambios específicos del evento están en la rama del evento . Si se realizan cambios en la rama maestra que también son necesarios en la rama del evento , use rebase ...

git rebase master

Otra respuesta sugirió la combinación de maestro en evento, pero el enfoque es generalmente una mejor base. Un rebase elimina las confirmaciones realizadas en la rama del tema, arrastra el maestro actualizado hacia adelante y luego vuelve a aplicar los cambios de la rama del tema en la parte superior ... como si los cambios de la rama del tema se hicieran a la versión más reciente del maestro.

En su escenario, cuando finalice el evento, simplemente elimine la rama del evento .