Estructura del repositorio mercurial con comunicaciones corporativas de gran peso, gestión de configuración y requisitos de prueba

16

Soy otro usuario de Subversion que lucha por reeducarme en el Tao del control de versiones distribuido.

Cuando usaba Subversion, era un gran admirador del enfoque de proyecto menor y, con la mayoría de mis antiguos empleadores, estructuraríamos nuestras sucursales de repositorio; Etiquetas y tronco de la siguiente manera:

branches-+
         +-personal-+
         |          +-alice-+
         |          |       +-shinyNewFeature
         |          |       +-AUTOMATED-+
         |          |                   +-shinyNewFeature
         |          +-bob-+
         |                +-AUTOMATED-+
         |                            +-bespokeCustomerProject
         +-project-+
                   +-shinyNewFeature
                   +-fixStinkyBug
tags-+
     +-m20110401_releaseCandidate_0_1
     +-m20110505_release_0_1
     +-m20110602_milestone
trunk

Dentro del propio árbol fuente, usaríamos (algo así) la siguiente estructura:

  (src)-+
        +-developmentAutomation-+
        |                       +-testAutomation
        |                       +-deploymentAutomation
        |                       +-docGeneration
        |                       +-staticAnalysis
        |                       +-systemTest
        |                       +-performanceMeasurement
        |                       +-configurationManagement
        |                       +-utilities
        +-libraries-+
        |           +-log-+
        |           |     +-build
        |           |     +-doc
        |           |     +-test
        |           +-statistics-+
        |           |            +-build
        |           |            +-doc
        |           |            +-test
        |           +-charting-+
        |           |          +-build
        |           |          +-doc
        |           |          +-test
        |           +-distributedComputing-+
        |           |                      +-build
        |           |                      +-doc
        |           |                      +-test
        |           +-widgets-+
        |                     +-build
        |                     +-doc
        |                     +-test
        +-productLines-+
        |              +-flagshipProduct-+
        |              |                 +-coolFeature
        |              |                 +-anotherCoolFeature
        |              |                 +-build
        |              |                 +-doc
        |              |                 +-test
        |              +-coolNewProduct
        +-project-+
                  +-bigImportantCustomer-+
                  |                      +-bespokeProjectOne
                  |                      +-bespokeProjectTwo
                  +-anotherImportantCustomer-+
                                             +-anotherBespokeProject

La idea era (y sigue siendo) usar la estructura del repositorio para ayudar a estructurar la comunicación entre el equipo de ingeniería; la parte del negocio orientada al cliente y otras partes interesadas y expertos en dominios.

A saber: los documentos de origen que se encuentran en uno de los directorios de "proyectos" se usan (y ganan dinero) solo una vez. Los documentos que se encuentran en uno de los directorios "productLines" ganan dinero tantas veces como se vende un producto de esa línea en particular. Los documentos que se encuentran en uno de los directorios de "bibliotecas" ganan dinero tantas veces como cualquiera de los productos que los usan se venden.

Hace explícita la noción de amortización de costos y ayuda a crear soporte para la reutilización de documentos fuente en toda la empresa.

También significa que existe una estructura común sobre la cual pueden operar nuestras herramientas de automatización de compilación. (Nuestros scripts de compilación recorren el árbol de origen en busca de carpetas de "compilación" dentro de las cuales encuentran archivos de configuración que especifican cómo se debe compilar cada componente; ocurre un proceso similar para la generación y prueba de documentación).

Significativamente, los productos en los que trabajo suelen tardar MUCHO tiempo en ejecutar pruebas de medición y caracterización del rendimiento; de 20 a 200 horas; generar en algún lugar entre varios GB y varios TB de resultados de prueba procesados ​​/ datos intermedios (que deben almacenarse y vincularse a una configuración de sistema particular para que se pueda medir la mejora del rendimiento a lo largo del tiempo). Este problema hace que la administración de la configuración sea una consideración importante, y también impone algunos requisitos para la centralización, ya que típicamente los recursos computacionales necesarios para ejecutar la medición del desempeño y las pruebas de caracterización son limitados; (un pequeño grupo de 64-128 núcleos).

Como una nota final; el sistema de integración continua sabe que necesita activar una compilación; análisis estático; la prueba de humo y la prueba de la unidad se ejecutan cada vez que se modifica la troncal, cada vez que se modifica cualquier rama "etiqueta", y cada vez que se modifica cualquier rama "AUTOMATIZADA". De esta manera, los desarrolladores individuales pueden usar el sistema CI con sus ramas personales, una capacidad importante, en mi humilde opinión.

Ahora, aquí está mi pregunta: ¿Cómo puedo replicar todo lo anterior (y mejorarlo, si es posible), con Mercurial.

--editar:

Mi línea de pensamiento actual es utilizar un repositorio central de Subversion, para definir la estructura general, pero permitir el uso de hg como cliente para que los desarrolladores puedan tener repositorios disponibles localmente.

William Payne
fuente
1
Guau. Una buena respuesta a esto será un ensayo muy largo, creo.
Ed James
Creo que la pregunta clave es cómo y dónde van las fusiones de código, ya que eso probablemente definirá el camino de menor resistencia. Entonces, ¿cómo se fusiona el código?
Wyatt Barnett
Por lo general, una fusión puede provenir de una rama personal en un proyecto o rama de características, y luego en el tronco. Nunca experimenté demasiadas dificultades con las fusiones (estábamos usando TortoiseSVN en Win32), aunque nunca corrimos durante demasiado tiempo (una iteración como máximo) sin integrar nuevamente en el tronco. De todos modos, tendíamos a hacer la mayor parte de nuestro trabajo en troncal, aunque el objetivo era simplificar la gestión de personal en lugar del flujo de trabajo de desarrollo. (Un desarrollador líder, muchos desarrolladores que trabajan de forma independiente, por lo que tener todo en el baúl hizo que sea más fácil para el desarrollador llevar un registro de lo que estaba sucediendo)
William Payne
Un punto clave fue una gran dependencia de las pruebas conducidas por el sistema CI, particularmente en el nivel de prueba del sistema. Esto fue para ayudar a construir la confianza de que diferentes desarrolladores no estaban interfiriendo entre sí, y para promover una mentalidad de muchas iteraciones pequeñas. (Además, el trabajo pesado computacional requerido para ejecutar las pruebas del sistema significaba que había menos contención por los recursos computacionales si las personas trabajaban principalmente en el tronco).
William Payne

Respuestas:

10

La respuesta de Spoike es excelente, pero hay algunas cosas que creo que valdría la pena agregar que son demasiado grandes para comentarios.

Organización de la sucursal

Con Mercurial puedes ignorar felizmente la totalidad de tu primer organigrama. Como dice Spoke, cada repositorio tiene su propio conjunto de etiquetas, ramas (con nombre y anónimo) y puede organizarse de acuerdo con las necesidades del negocio.

Si bespokeProjectTwonecesita una versión especial de la chartingbiblioteca, entonces se ramificaría charting, agregaría las nuevas instalaciones y la usaría bespokeProjectTwo. Las nuevas instalaciones (y sus errores) no serían utilizadas por otros proyectos que harían referencia a la chartingbiblioteca estándar . Si la chartingbiblioteca principal tuviera errores corregidos, podría fusionar esos cambios en la rama. Si otros proyectos también necesitaran estas instalaciones, puede hacer que esos proyectos usen la rama especial o fusionar la rama en la línea principal y cerrar la rama.

Además, no hay nada que le impida tener una política para estructurar los nombres de las sucursales para proporcionar servicios específicos como sus sucursales de AUTOMATION.

Organización del directorio

No hay ninguna razón por la que no pueda mantener su directorio de origen exactamente como está con Mercurial. La única diferencia es que, mientras que con Subversion tiene un único (src)repositorio monolítico , con Mercurial es mejor dividirse en repositorios que están agrupados lógicamente. De su estructura de árbol de origen, probablemente extraería cada uno de los siguientes como repositorios individuales:

src-+
      +-(developmentAutomation)
      +-libraries-+
      |           +-(log)
      |           +-(statistics)
      |           +-(charting)
      |           +-(distributedComputing)
      |           +-(widgets)
      +-productLines-+
      |              +-(flagshipProduct)
      |              +-(coolNewProduct)
      +-project-+
                +-bigImportantCustomer-+
                |                      +-(bespokeProjectOne)
                |                      +-(bespokeProjectTwo)
                +-anotherImportantCustomer-+
                                           +-(anotherBespokeProject)

Esto permite que cualquier producto o proyecto a medida use cualquier combinación de bibliotecas, en cualquier revisión. Eche un vistazo a los repositorios mercuriales para una manera fácil de administrar qué bibliotecas se utilizan para cualquier versión dada de un producto o proyecto.

Flujo de trabajo

Una alternativa al flujo de trabajo sugerido por Spoike (el desarrollador extrae del bendito repositorio, trabaja localmente, emite una solicitud de extracción y finalmente el integrador extrae esos cambios y los fusiona) sería utilizar el sistema de integración continua como intermediario.

Como antes, el desarrollador se retira del repositorio bendecido y trabaja localmente, pero cuando lo hace, se retira del repositorio bendecido nuevamente y se fusiona antes de pasar a un repositorio sin bendiciones. Cualquier cambio en el repositorio no bendecido se revisa (de forma manual o automática) y se traslada al repositorio bendecido solo si se aprueba.

Esto significa que el integrador solo tiene que aceptar o rechazar un cambio, no hacer la fusión. En mi experiencia, casi siempre es mejor para el desarrollador que escribió el código realizar la fusión que para que otra persona lo haga.

Como se sugiere en el libro de mercurial, se pueden usar ganchos para automatizar este procedimiento:

Cuando alguien empuja un conjunto de cambios al servidor del que todos extraen, el servidor probará el conjunto de cambios antes de aceptarlo como permanente y lo rechazará si no pasa el conjunto de pruebas. Si las personas solo extraen cambios de este servidor de filtrado, servirá para garantizar que todos los cambios que las personas extraen se hayan examinado automáticamente.

Otros asuntos

El problema de los grandes conjuntos de datos de prueba también se puede resolver colocando esos datos de prueba en un sub-repositorio mercurial . Esto evitará que el repositorio de código se hinche con datos de prueba, mientras mantiene los datos de prueba bajo control de revisión.

Mark Booth
fuente
Nuevamente, otra excelente e informativa respuesta. Gracias.
William Payne
RE: Organización de la sucursal. Estoy de acuerdo en que el primer organigrama puede ser felizmente ignorado. De todos modos, no comunicaba el flujo de trabajo particularmente bien, por lo que no proporcionaba ninguna utilidad real más allá de reforzar la convención. Sin embargo, me gustaría reemplazarlo con algo que comunique fuertemente un flujo de trabajo (lo más simple posible) y aliente los compromisos frecuentes. ¿Quizás llamar a la rama principal "troncal / desarrollo" "diariamente" haría eso?
William Payne el
RE: Organización del directorio. Estaba usando la organización del directorio fuente como un medio subliminal de comunicación; imponiendo una estructura implícita en la organización del código (y a través de eso en el negocio en su conjunto). Estoy empezando a entender que Mercurial tiende a usarse de una manera muy muy flexible; pero realmente quiero limitar algo de esa flexibilidad para imponer una estructura en la forma en que las personas piensan sobre el negocio al imponer una estructura en la forma en que sus documentos están organizados en sus estaciones de trabajo y en nuestras áreas de almacenamiento de red. (Más comunicaciones corporativas que tecnología.)
William Payne
RE: flujo de trabajo. Creo que el flujo de trabajo más simple sería extraer de un repositorio "diario", trabajar en él localmente y luego (con frecuencia) retroceder al repositorio "diario", iniciando el análisis estático, las pruebas de humo y las pruebas de regresión a través del sistema CI. Estoy feliz de que el repositorio principal esté "roto", siempre que lo sepa, y siempre que se arregle de nuevo rápidamente. De hecho, estoy considerando hacer que comprometerse con el repositorio "diario" sea la única forma en que uno puede compilar y construir, para alentar compromisos frecuentes y una buena cobertura de prueba. (Mucho más importante que la capacidad de trabajar de forma aislada, en mi humilde opinión).
William Payne
@WilliamPayne - Gracias. Si bien Mercurial es flexible, con los repositorios, las ramas y los ganchos adecuados, puede incorporar las restricciones que desee, a nivel organizativo o de repositorio. Personalmente, comenzaría simplemente con controles organizativos y algunos ganchos de CI, y ampliaría esos controles en el futuro a medida que su necesidad se haga evidente. Además, el uso juicioso de los repositorios secundarios podría, por ejemplo, alentar a las personas a que revisen las cosas localmente en la misma estructura que en el servidor, por ejemplo al tener productLineso bigImportantCustomercomo repositorios superiores.
Mark Booth el
9

Bien, tratando de responder esto simplemente.

Lo que necesitas saber

Lo primero que debe saber: Mercurial es un control de versión distribuido y tiene algunas propiedades que debe conocer enumeradas a continuación.

  • La fuente proviene de un repositorio, donde ese repositorio se puede clonar. Todos los repositorios clonados pueden compartir código entre sí a través de la sincronización (con comandos pull y push, que pueden tener acceso restringido).
  • Cada usuario que tiene una copia del código, tiene un clon del repositorio. Si quieren ramificarse, pueden hacerlo en su clon local. Eso significa que no necesita organizar cómo debe ramificarse cada usuario. Pueden hacer esto por sí mismos.
  • Las etiquetas se crean en mercurial mediante una confirmación (que es lo mismo que las etiquetas duras en git). Esto significa que no necesita un directorio dentro de su estructura de repositorio para las etiquetas.
  • El modelo habitual con el que las personas trabajan en DVCS (que se emplea en github y bitbucket) es hacerlo semi-centralizado.

    Cada usuario tiene un repositorio público (en algunos recursos compartidos o en un servidor seguro) y un repositorio privado (en sus propias estaciones de trabajo). Ambos son clones del repositorio "bendecido" de un integrador. Cada vez que sienten que están listos para publicar su código, pueden enviar los cambios a su repositorio público. Un integrador puede elegir qué usuarios extraer código en el repositorio "bendito".

    Si el integrador no puede fusionar fácilmente el código de algún usuario, entonces los cambios se rechazan y corresponde a ese usuario en particular actualizar su repositorio y arreglar la fusión ellos mismos. Por lo general, no es tan difícil si se fusiona con frecuencia (ya que es menos el código que debe fusionarse) y, por lo general, ese usuario debe saber qué salió mal con la fusión.

Configuración de repositorios por proyecto

Entonces, la configuración habitual es que para cada proyecto hay lo siguiente:

  • Un repositorio público de solo lectura del que es responsable el integrador. Es "bendecido".

    Es decir, todos los usuarios pueden extraer / recuperar contenido, pero no tienen acceso para enviarlo.

  • Cada usuario puede tener su propio clon público del repositorio.

    La configuración más sencilla se coloca en una unidad compartida (aunque podría considerar hospedar como bitbucket). El integrador recibe solicitudes de extracción de los usuarios e intenta extraer el nuevo código de estos repositorios. Cuando las fusiones se realizan sin problemas, se coloca en el repositorio de solo lectura. De lo contrario, se les pide a los usuarios que solucionen los conflictos de fusión que surgen actualizándolos y fusionándolos localmente.

  • Cada usuario puede tener sus propios clones privados del repositorio.

    Una buena práctica es sacar de su clon público, pero no importa si sacan de su público o del integrador. Todos los commits son identificables de manera única, por lo que fusionar los commits que olvidó buscar en el público es relativamente fácil de arreglar (al impulsar los cambios de lo privado a lo público, también obtiene automáticamente los cambios del integrador).

Organización del código fuente

En cuanto a cómo organizar la fuente del proyecto en sí, es algo en lo que debe pensar. Si un artefacto necesita ser controlado por la fuente, entonces póngalo en control de la fuente. Personalmente, no me gusta la idea de registrar artefactos creados por la compilación o el tiempo de ejecución (debido al alto riesgo de conflictos de fusión en este tipo de artefactos), como archivos binarios o archivos de registro.

También puede verificar la configuración, siempre que facilite la puesta en marcha de los desarrolladores y no altere la configuración de las versiones o el entorno de producción / en vivo (como la configuración de la aplicación / servidor web). Esto lleva a la noción de que si la configuración que tiene obstaculiza seriamente a los desarrolladores para comenzar dentro de los cinco minutos posteriores a la verificación del código, entonces debe ser refactorizado. Otro requisito es que debería ser muy difícil para los desarrolladores estropear el lanzamiento o el entorno de producción / en vivo.

Usted menciona que tiene datos de prueba que deben estar vinculados a alguna versión del código. Ahora, esto es un poco más complicado porque los sistemas DVCS como Mercurial y Git tienden a ser más lentos cuando ingresas datos que son ENORMES. En mi experiencia, se vuelve realmente insoportable después de 5 GB de archivos binarios (su kilometraje puede variar, por lo que debe probar cómo funciona para usted). Sin embargo, recomendaría que coloque los datos generados en su propio repositorio y que su sistema de prueba los etiquete adecuadamente cuando los registre (y / o cree archivos de texto para los mismos fines de metadatos).

Espero que todo esto tenga sentido. Comenta a continuación si me perdí algunos detalles o si algo necesita más explicaciones e intentaré editarlo.

Spoike
fuente
+1 para una respuesta muy agradable con varios puntos muy útiles. En respuesta a la primera sección de su respuesta, no había comprendido la importancia de que cada usuario tenga su propio repositorio público. Tal vez necesito pensar más sobre cómo se podrían organizar los flujos de trabajo entre pares.
William Payne
En respuesta a la segunda sección de su respuesta, el punto (en mi opinión) de tener un único repositorio para toda la organización es crear una imagen mental compartida de cómo se estructura el trabajo y facilitar la búsqueda de componentes que puedan ser reutilizado (Mucho más la Catedral que el Bazar, pero ese es el entorno en el que trabajo). Realmente me gustaría saber cómo lograr el mismo sentido de organización estructurada (sistema de archivo) con un DCVS.
William Payne
En respuesta a la tercera sección de su respuesta: estoy totalmente de acuerdo en que el sistema de control de origen es para los documentos de origen, y los artefactos derivados no pertenecen allí. También estoy de acuerdo en que no es práctico almacenar grandes binarios de cualquier descripción en VCS. Sin embargo, creo que puede almacenar grandes binarios en una ubicación de red acordada, con un nombre definido, y hacer referencia a ellos desde el VCS. Por ejemplo, los entornos de compilación se pueden almacenar como imágenes de disco VM con nombre, y se puede hacer referencia a ellos desde los diversos scripts de compilación. (por ejemplo: compilarme en build_env_A). Lo mismo vale para los datos de prueba.
William Payne
En el pasado, he usado una jerarquía de directorios en una unidad de red, donde los nombres de directorio se derivan del número de revisión de subversión + hash de ubicación de sucursal para vincular archivos intermedios y resultados de pruebas a revisiones particulares. Esto significa que tenemos trazabilidad sin necesidad de almacenar archivos derivados en el control de versiones.
William Payne