2010-09-15 16 views
17

Esta es una pregunta de mejores prácticas, y espero que la respuesta sea "depende". Solo espero aprender más escenarios y flujos de trabajo del mundo real.¿Cómo administrar el desarrollo simultáneo con mercurial?

En primer lugar, estoy hablando de diferentes cambios para el mismo proyecto, por lo que no hay subrepo por favor.

Digamos que tiene su código base en un repositorio de hg. Empiezas a trabajar en una nueva y complicada función A, luego tu brigadista de confianza informa sobre un bug B complicado (tienes testers, ¿no?).

Es trivial si (la solución para) B depende de R. simlply CI a continuación ci B.

Mi pregunta es qué hacer cuando son independientes (o al menos eso parece ahora).

puedo pensar en las siguientes maneras:

  1. Utilice un clon independiente para B.
  2. Use ramas anónimas o con nombre, o marcadores, en el mismo repositorio.
  3. Use MQ (con parche B en la parte superior de A).
  4. Usar MQ ramificado (lo explicaré más adelante).
  5. Uso MQ múltiple (desde 1,6)

1 y 2 están cubiertos por una excellent blog por @Steve de Losh enlazadas desde una slightly related question.

La gran ventaja de 1 sobre las otras opciones es que no requiere ninguna reconstrucción cuando se pasa de trabajar en una cosa a otra, porque los archivos están físicamente separados e independientes. Entonces, realmente es la única opción si, por ejemplo, A y/o B tocan un archivo de cabecera que define un booleano tri-estado y está incluido en miles de archivos C (no me diga que no ha visto un código heredado base).

3 es probablemente el más fácil (en términos de configuración y sobrecarga), y puede cambiar el orden de A y B si B es una solución pequeña y/o urgente. Sin embargo, puede ser complicado si A y B tocan el (los) mismo (s) archivo (s). Es fácil solucionar problemas de parches que no se aplicaron si los cambios A y B son ortogonales dentro del mismo archivo (s), pero conceptualmente sigue siendo un poco arriesgado.

4 puede marearlo, pero es la forma más potente, flexible y escalable. De manera predeterminada, hg qinit con -c, ya que quiero marcar parches de trabajo en progreso y empujarlos/tirarlos, pero da un salto conceptual para darse cuenta de que también puede bifurcar en el repositorio de MQ.Estos son los pasos (mq = hg --mq):

  1. hg qnew bugA; hacer cambios para A; hg qref
  2. mq branch branchA; hg qci
  3. hg qpop; mq up -rtip^
  4. hg qnew bugB; hacer cambios para B; hg qref
  5. mq branch branchB; hg qci
  6. para trabajar en un nuevo: hg qpop; mq up branchA; hg qpush

Parece una locura tomar tantos pasos, y cada vez que necesite cambiar el trabajo que debe hg qci; hg qpop; mq up <branch>; hg qpush. Pero tenga en cuenta esto: tiene varias sucursales de publicación nombradas en el mismo repositorio, y necesita trabajar en varios proyectos y correcciones de errores al mismo tiempo para todos ellos (será mejor que obtenga una bonificación garantizada para este tipo de trabajo). Te perderías muy pronto con los otros enfoques.

Ahora mis compañeros amantes de hg, ¿hay otras/mejores alternativas?


(UPDATE) qqueue casi hace # 4 obsoleto. Ver la descripción elegante de Steve Losh here.

+0

Como si no fuera obvio, estoy pidiendo un enfoque basado en hg. Pero si puedes darme un solo comando de otro SCM que funcione en todos los casos, estoy abandonando hg. Considéralo un desafío, git aficionados. –

+1

Creo que necesita especificar su problema un poco mejor. ¿Por qué esto no funciona para todos los casos: corregir el error A, confirmar su parche, corregir el error B, confirmar su parche? – Karmastan

+0

Perdón por haber hablado un poco, Spolsky-ishly. Mencioné un caso simple: "si B es una solución pequeña y/o urgente". Una situación más realista es que A y B son proyectos largos que requieren una gran cantidad de compromisos e iteraciones. Además, si tiene un proceso de revisión de código como lo hace mi empresa, es posible que haya terminado A y lo haya enviado para su revisión, y que no pueda quedarse sentado allí esperando a los revisores, así que tendrá que ir a recoger B mientras tanto. . Pero luego el revisor puede explotar tu código y tienes que hacer cambios para complacerlo. Así que puede haber innumerables interruptores de proyectos en el camino. –

Respuesta

3

Parece que no hay más opciones o mejores que las que figuran en la pregunta. Entonces aquí están otra vez.

  1. Use una copia por proyecto.
    • Pros: separación total, por lo tanto, no hay reconstrucción al cambiar de proyecto.
    • Contras: toolchain necesita cambiar entre dos clones.
  2. Use ramas anónimas o con nombre, o marcadores, en el mismo repositorio.
    • Pros: práctica de hg estándar (o cualquier DVCS); limpio y claro.
    • Contras: debe confirmar antes de cambiar y reconstruir después.
  3. Utilice MQ con un parche (o parches consecutivos múltiples) por proyecto.
    • Pros: simple y fácil.
    • Contras: debe qrefresh antes de cambiar y reconstruir después; complicado y arriesgado si los proyectos no son ortogonales.
  4. Utilice una rama de MQ (o qqueue en 1.6+) por proyecto.
    • Pros: de ultra flexible y escalable (para el número de proyectos concurrentes)
    • Contras: debe qrefresh y qcommit antes de cambiar y reconstruir después; se siente complicado

Como siempre, no hay bala de plata, por lo que escoger y elegir el más adecuado para el trabajo.


(UPDATE) Para cualquier persona que está enamorada de MQ, MQ utilizando en la parte superior de las ramas regulares (# 2 + # 3) es probablemente la práctica más común y preferible.

Si tiene dos proyectos concurrentes con la línea de base en dos ramas (por ejemplo próxima versión y la versión actual), es trivial para saltar entre ellos de esta manera:

hg qnew; {coding}; hg qrefresh; {repeat} 
hg qfinish -a 
hg update -r <branch/bookmark/rev> 
hg qimport -r <rev>; {repeat} 

Para el último paso, qimport debe agregar una -a opción para importar una línea de conjuntos de cambios a la vez. Espero que Meister Geisler note esto :)

7

Siempre usaría ramas con nombre, porque eso permite a Mercurial hacer su trabajo: mantener el historial de su proyecto y recordar por qué hizo qué cambios en qué orden para su código fuente. Ya sea para tener un clon o dos sentado en su disco es generalmente una tarea fácil, dada mi estilo de trabajo, al menos:

  1. ¿Su proyecto carecen de un proceso de construcción, de modo que usted puede probar y ejecutar las cosas bien desde el código fuente? Entonces tendré la tentación de tener solo un clon, y hg up de ida y vuelta cuando necesite trabajar en otra sucursal.

  2. Pero si tiene un buildout, virtualenv, u otra estructura que se construye, y que puede divergir entre las dos ramas, entonces hacer un hg up luego esperar a que el proceso de compilación vuelva a ejecutarse puede ser un gran dolor, especialmente si se trata de configurar una base de datos de muestra. En ese caso, definitivamente usaría dos clones, uno en la punta del maletero y otro en la punta de la rama de emergencia.

+0

Voté pero no acepté esto porque mencioné la rama nombrada yo mismo, y estaba pidiendo alternativas :) Tenemos un proceso de compilación (no muy moderno, como la base de código en sí misma), así que el n. ° 2 es de hecho el argumento para usar dos clones. Sin embargo, puede ser complicado cambiar el flujo de trabajo de depuración entre los dos clones; por ejemplo, necesitaría dos configuraciones de inicio en Eclipse. –

+1

Como alternativa a las ramas nombradas, puede numerarlas :) En otras palabras, no hay una buena alternativa, la rueda ya se ha inventado. –

1

Entonces la pregunta es, en el momento en que se les dice que dejar de trabajar en función de A, B y empezar rasgo independiente, ¿qué opciones alternativas están ahí, para: Cómo gestionar el desarrollo concurrente con mercurio?

Analicemos el problema con la eliminación de simultaneidad, de la misma forma que se escribe el código enhebrado: defina un flujo de trabajo simple para resolver cualquier problema que se le haya asignado y aplíquelo a cada problema. Mercurial se unirá al trabajo una vez que lo haya hecho. Por lo tanto, el programador A trabajará en la característica A. El programador B trabajará en la característica B. Ambos simplemente son usted. (Si tuviéramos cerebros multi-core :)

Siempre usaría ramas con nombre, porque eso permite a Mercurial hacer su trabajo: mantener el historial de su proyecto, y recordar por qué hizo qué cambios en qué orden su código fuente

Estoy de acuerdo con el sentimiento de Brandon, pero me pregunto si pasó por alto que la característica A no se ha probado? En el peor de los casos, el código compila y pasa pruebas unitarias, pero algunos métodos implementan los requisitos anteriores, y algunos métodos implementan los nuevos. Una diferencia con respecto al registro anterior es la herramienta que utilizaría para ayudarme a volver a la pista con la función A.

¿Su código para la función A está en un punto cuando normalmente lo registraría? El cambio de la característica A a la función B no es un motivo para confirmar el código en la cabeza o en una rama. Solo ingrese el código que compila y pasa sus pruebas. Mi razón es que, si el programador C necesita comenzar la función C, una nueva extracción de esta sucursal ya no es el mejor lugar para comenzar. Mantener saludables las cabezas de las ramas, significa que puede responder rápidamente, con correcciones de errores más confiables.

El objetivo es tener su código (probado y verificado) en ejecución, por lo que desea que todo su código termine fundido en la cabeza (de su desarrollo y ramas heredadas). Mi punto parece ser que he visto que la bifurcación se usa de manera ineficiente: el código se vuelve obsoleto y luego no se usa, la fusión se vuelve más difícil que el problema original.

Solo su opción 1 tiene sentido para mí. En general:

  1. Debería pensar que su código funciona, antes de que alguien más lo vea.
  2. Coloque la cabeza sobre una rama.
  3. Branch y check-in si alguien más está recogiendo el problema.
  4. Branch si su sistema automatizado o probadores necesitan su código solamente.
  5. Branch si eres parte de un equipo, trabajando en un problema. Considéralo la cabeza, mira 1-4.

Con la excepción de los archivos de configuración, los procesos de compilación deben ser una extracción y un único comando de compilación. No debería ser más difícil cambiar entre clones que un programador nuevo para unirse al proyecto. (Voy a admitir que mi proyecto necesita algo de trabajo aquí.)

+0

gracias por la respuesta, pero parece que lo está abordando en el contexto de un VCS tradicional (centralizado) como svn. En hg (o cualquier DVCS) sus confirmaciones son locales hasta que sean empujadas/tiradas, por lo que es perfecto (y recomendable) para confirmar antes de realizar la prueba. –

+0

Uso principalmente svn, así que estoy seguro de que afecta mi perspectiva. En hg, después de un empujón, ¿el registro muestra una diferencia entre la confirmación de envío y las confirmaciones locales? ¿Usas github? Es genial, pero puede ser difícil averiguar qué repositorio clonar: qué bifurcación contiene las correcciones de errores que necesitas, o qué activo o abandonado. Volviendo a la bifurcación, puedo ver cuántos puntos de confirmación ayudan al autor. Creo que estás diciendo que hg protege a otros desarrolladores para que no vean las confirmaciones provisionales, porque no están presionadas. Creo que las pruebas de integración son donde esto podría no ser cierto. –

+0

lo siento, no he notado su comentario. Una vez que se envían los commit (más exactamente, los conjuntos de cambios), ya no son locales. El registro no muestra si se ha presionado un conjunto de cambios. El comando 'outgoing' te dice si no lo ha hecho. No hay "protección" en los compromisos locales. Cualquiera puede tirar de ellos si lo desean. –

Cuestiones relacionadas