Git: evita que se agregue un directory de desarrollo en la fusión

Soy un progtwigdor que está más familiarizado con lenguajes de progtwigción de alto nivel como C # o Python, pero recientemente comencé a trabajar más en las complejidades de Git. Context: estoy desarrollando un juego, y tengo una twig de development con un directory específico de 'Development' que no será empujado a master en una combinación, por el bien de mantener el master limpio.

Llegué a esta respuesta que casi hace el trabajo; sin embargo, este método, si bien no confirmará los cambios en el directory, aún lo crea en la twig master , lo que significa que después de cada fusión, todavía tendría que volver atrás y eliminar los files manualmente.

Estoy configurando un alias git publish para automatizar esta tarea, la cual publicaré aquí para completarla:

 [alias] publish = "!f(){ git checkout master \ && git merge --no-commit --no-ff development \ && git reset -- Assets/Development/ \ && git commit \ && git push; };f" 

Me gustaría saber si hay alguna forma de evitar que se creen los Assets/Development/ en master .

Nota al .gitignore : .gitignore violín con .gitignore no ayudará, debido a la naturaleza de .gitignore , que no son realmente "files para ignorar", sino más bien "files para suprimir ciertas quejas sobre, y / o para sentirse libre de destruir en algunos casos". (Esto no significa que no deba ajustar .gitignore por otros motivos, solo que no ayudará con este problema de combinación, porque realmente desea que los files se versionen en la twig de desarrollo).

Su solución actual (y forms de mejorarla tal vez)

Un truco es básicamente lo que estás haciendo ahora: hacer la fusión (con --no-commit ), luego quitar las cosas que no querías.

El paso de strip-out es este:

 git reset -- Assets/Development/ 

Utiliza la forma --mixed (pnetworkingeterminada y forzada cuando das routes) de git reset , que establece (o "reinicia", realmente) el índice para que coincida con el tree especificado para la (s) ruta (s) especificada (s). Aquí el path es Assests/Development/ , es decir, todo dentro de ese subdirectory. El tree especificado no está especificado, por lo que tiene el encabezado HEAD , o más bien, el tree para HEAD . HEAD es la confirmación actual de la twig actual, que es, por supuesto, master ya que acabamos de verificarla; y master no contiene Assets/Development/ en absoluto, por lo que el índice de restablecimiento ahora ya no tiene ese subtree.

En resumen, porque Assets/Development/ no está en HEAD , esto deshace los git add s que git merge hizo en todo en Assets/Development . El problema es que, si bien esto elimina las inputs del índice , las deja en el tree de trabajo .

Se podría intentar git reset --hard -- Assets/Development/ pero git no lo hará: no se puede especificar un modo de reinicio al dar routes. Eso deja tres opciones más obvias, sin embargo:

  • agregue rm -r Assets/Development (justo antes o justo después del git reset , o incluso después del paso de commit )

    Esto elimina los files, por lo tanto, con ellos desde el índice y el tree de trabajo, puede comprometerse y hacerse.

  • use git rm -rf Assets/Development/ (en lugar del git reset )

    Esto elimina las inputs de índice y elimina los files del tree de trabajo (y el directory), por lo que puede confirmar y finalizar.

  • use git clean después de cometer. Esto puede hacer más de lo que quieras.

Lo principal es que solo debes hacer esto una vez, no repetidamente. Depende de qué cambios hagas a lo largo del path.

Más sobre fusión

Cuando ejecutas git merge <commit> , primero git encuentra la base de combinación .

La base de fusión se define como el antecesor común de L ow (LCA) en el gráfico de confirmación entre dos nodos en el gráfico. Los dos nodos son su confirmación actual, en este caso, la punta del master de sucursal, y la confirmación que se le da a git merge , que en este caso es la confirmación de punta del development de la sucursal. La definición de LCA requiere un poco de teoría de grafos, pero en términos generales, es la confirmación "más cercana" que está en ambos historiales de compromiso.

Para ver cómo funciona esto, ayuda dibujar parte del gráfico de compromiso. Aquí tenemos master y development como dos sugerencias de twigs, con las dos estructuras de twigs (cadenas de compromisos) que finalmente se unen:

 ... <- o <- * <- o <- ... <- o <-- master \ o <- o <- ... <- o <-- development 

La confirmación marcada con * es la base de fusión: es el punto en el que el development y el master vuelven a join, y el compromiso * y cada confirmación anterior está en ambas twigs, en lugar de estar solo en uno.

Lo que merge en este punto es generar dos diferencias: una desde * hasta la punta de la confirmación actual (la sugerencia de confirmación en el master ) y una de * a la otra, objective, confirmar (la punta del development ).

En master tienes algunos (probablemente no demasiados) cambios desde * , y en development tienes un montón de cambios, incluyendo la adición de Assets/Development/ .

El command de merge combina los cambios, que incluyen agregar el directory no deseado. Cuando todo termina, git realiza una nueva confirmación (el paso --no-ff garantiza; si la combinación de fusión * la punta del master , que no es lo que dibujamos, pero es posible en la primera fusión, git intentará hacer una label de avance rápido en lugar de hacer una fusión real).

El resultado es un gráfico que ahora se parece más a esto (voy a dejar de dibujar en las flechas que apuntan hacia la izquierda, solo tenga en count que el historial va hacia la izquierda, es decir, más tarde confirma el punto de return a los anteriores):

 ...--o--*--o-...-o---o <-- master \ / o--o-...-o <-- development 

Ahora continúas desarrollándote en development , haciendo más commits nuevos. Reemplacemos * con o ya que ya no es un caso especial.

 ...--o--o--o-...-o---o <-- master \ / o--o-...-o--o--o <-- development 

y en algún punto decides volver a fusionarte, así que echas un vistazo a master y le dices a git merge que encuentre el (nuevo) consejo de development y que calcule la base de fusión.

La base de combinación es, nuevamente (y un poco flojo), la primera confirmación que está en ambas twigs. Vamos a encontrarlo: ¿es lo mismo que antes? Comience en las puntas de ambos master y development y trabaje al revés de cada uno, coloreando nodos con dos colors diferentes. Tan pronto como un nodo obtiene ambos colors, es un ancestro común. El más cercano a las puntas es el "más bajo", es decir, es la base de fusión.

No puedo dibujar colors, pero si haces el ejercicio tú mismo, verás que es este nodo:

 ...--o--o--o-...-o---o <-- master \ / o--o-...-*--o--o <-- development 

El nodo ahora marcado * es accesible desde el master (siguiendo el segundo padre hacia abajo y hacia la izquierda), y desde el development (siguiendo la cadena a la izquierda). Es el nodo más cercano, por lo que es la base de combinación.

Git ahora diffs la base de combinación * contra los dos consejos. Debe haber pocos o ningún cambio en la punta del master (básicamente solo lo que fue recogido de los nodos entre la base de fusión previa y la nueva sugerencia del master ), y los cambios que haya realizado en la twig de development desde la última fusión .

Si esos cambios afectan los files existentes en Assets/Development , esos cambios causarán un conflicto de fusión:

 CONFLICT (modify/delete): Assets/Development/foo deleted in HEAD and modified in development. Version development of Assets/Development/foo left in tree. Automatic merge failed; fix conflicts and then commit the result. 

Tenga en count que no necesita el --no-commit para estos.

Si esos cambios agregan nuevos files en Assets/Development/ , por otro lado, merge los agregará felizmente a la confirmación que está a punto de hacer, por lo que necesita --no-commit para evitar agregar dichos files.

Puede volver a utilizar git rm -rf para lanzar cualquier conflicto y / o file agregado, si es necesario.