Pregunta

Estamos usando la subversión (la pregunta podría ser aplicable a muchos sistemas de control de versiones, pero la subversión es la que realmente me importa).

El diseño de nuestro repositorio se ve así:

(Diseño A)

Web
  branches
  tags
  trunk
Libraries
  Foo
    branches
    tags
    trunk
  Bar
    branches
    tags
    trunk
WindowsClient
  branches
  tags
  trunk
DB
  branches
  tags
  trunk

El problema es que la unidad de control de versiones no es igual a la unidad de desarrollo: tengo que hacer varios pagos para obtener un artefacto construible, y cuando ramifico, tengo que ramificar múltiples componentes (y registrar en múltiples lugares.)

Esto implica que podríamos movernos a una estructura como esta:

(Diseño B)

Web
  branches
  tags
  trunk
    main
    libs
      Foo
      Bar
    DB
WindowsClient
  branches
  tags
  trunk
    main
    libs
      Foo
      Baz
    DB

Pero luego tenemos copias duplicadas de cualquier biblioteca compartida. Podríamos asignar las bibliotecas compartidas al usar svn: externals, pero eso es solo una ilusión: no se ramificarán cuando el proyecto que lo contiene sea.

Una opción final es esta:

(Diseño C)

branches
tags
trunk
  Web
  Libraries
    Foo
    Bar
  WindowsClient
  DB

Esto asegura que las bibliotecas se ramifiquen junto con su proyecto contenedor, pero a costa de que la unidad de ramificación sea el mundo entero. (Esto también implica que la unidad de pago es el mundo entero, lo que también es molesto).

Lo que quiero es un diseño de repositorio (Diseño D) que me permita:

  • Ramifique un proyecto y sus bibliotecas dependientes a la vez
  • Compartir bibliotecas entre proyectos

Sería bueno si pudiera ver el proyecto y sus bibliotecas en un solo pago, pero eso no es tan importante como lo anterior.

Entonces la pregunta es:

¿Hay un diseño D, qué es y cómo lo uso?

Editar: Dado que parece que no hay un diseño básico que me otorgue estas propiedades, estaría muy interesado en algún tipo de función de enlace para llegar allí. Sería especialmente bueno si funcionara con el cliente TortoiseSVN (GUI de Windows), ya que eso es lo que estamos usando.

¿Fue útil?

Solución

Vaya con la opción C, luego realice sus pagos de esta manera:

svn co -N ...../branches/mybranch workingcopy
cd workingcopy
svn update Web Libraries

Ahora, cuando realiza operaciones svn (incluida una simple " svn update "), solo se ocupará de las bibliotecas Web y directorios.

Lea también en directorios dispersos .

Otros consejos

¿No hay una buena respuesta para la pregunta de cómo diseñar mi repositorio para este flujo de trabajo? porque el software realmente no soporta eso. Sugeriría ir con su diseño B, bifurcar el código de la biblioteca y cambiar el svn: external relevante a esa rama según sea necesario, o de inmediato si sus ramas necesitan referirse a una versión fuera del tronco de la biblioteca

Iba a sugerir que Git maneja esto mejor, pero no es mucho. Dado que sus submódulos se refieren a repositorios separados ligeramente diferentes de los externos, y cada copia del repositorio es una 'rama', eso podría ser una ligera mejora.

  

Podríamos mapear las bibliotecas compartidas al usar   svn: externos, pero eso es solo un   ilusión - no serán ramificados   cuando el proyecto que contiene es.

En realidad, se ramificarán si están en el mismo repositorio y usaste la sintaxis externa relativa, por ejemplo. ^ \ mylib \ trunk . Dichas referencias externas se cambian a carpetas normales (copiadas). Tiene que pasar explícitamente --ignore-externals a svn copy para suprimir este comportamiento, o de lo contrario terminará con copias como en el diseño B. ( editar : estaba bastante seguro de que funcionó de esta manera, pero parece que no puedo reproducir ese comportamiento. Debo haberme equivocado, ¡lo siento!)

El hecho de que los elementos externos no siempre se ramifiquen automáticamente no tiene por qué ser un problema. Utilizaría el diseño B construido con svn: externals (no copias), ramifique el proyecto (con --ignore-externals ), luego, después de la ramificación, adapte svn: externals para que apunte a la Corregir las ramas de la biblioteca.

Puede configurar los elementos externos para que apunten a una revisión específica (bueno para un control estricto; usted decide cuándo actualizar a una nueva revisión de la biblioteca) o simplemente realizar un seguimiento de la CABEZA (bueno para una integración continua, suponiendo que tenga una configuración del servidor de compilación).

La forma en que lo hemos resuelto es para bibliotecas externas compartidas utilizadas por varios proyectos, la biblioteca compartida va en su propio repositorio con su propio tronco / ramas / etiquetas.

Luego tenemos una compilación del servidor de compilación y publicamos compilaciones de integración, hitos y lanzamientos, y el artefacto binario se copia en una ubicación compartida y se almacena en directorios específicos de la versión (estos están respaldados).

Parte del script de compilación para un proyecto dependiente (normalmente se ejecuta bajo demanda como un inicio / actualización en lugar de como parte de una compilación estándar) luego busca nuevas versiones y toma el binario. Esto tiene la ventaja de tener versiones consistentes del artefacto compartido entre proyectos dependientes y reduce el tiempo de construcción ya que todos los proyectos dependientes pueden compartir la misma versión.

Para ayudar con el control de versiones, actualmente utilizamos Apache Ivy que admite cosas como dependencias transitorias (es decir, buscar las dependencias de una dependencia) y restricciones de versión (por ejemplo, este proyecto solo debe usar Foo versión 1.2. *).

Sugeriría que es su enfoque a estas bibliotecas lo que está causando sus problemas. Puede cambiar esto si comienza a pensar en las bibliotecas como proyectos separados por derecho propio. Piense en ellos como teniendo sus propias razones de ser, su propio diseño y sus propios ciclos de lanzamiento, al igual que las bibliotecas de terceros que puede usar para pruebas unitarias, lectores xml, acceso db, etc.

Por supuesto, regularmente tendrá momentos en los que una característica de un proyecto requiere una nueva característica en una biblioteca. La implementación de la función de biblioteca y el uso de la función de biblioteca son dos tareas independientes: pueden ser una tarea empresarial pero son dos tareas de desarrollo. No es necesario vincular estrechamente las dos actividades solo porque así es como surgió el trabajo. Revise la biblioteca, cámbiela, libérela, luego verifique su proyecto y use la nueva versión de la biblioteca en su proyecto.

Creo firmemente que tener bibliotecas separadas en sus propios troncos es algo bueno, no puedo soportarlo cuando veo múltiples proyectos liberables independientemente bajo un solo tronco. Parece un mal diseño y haber sido arrinconado por una ruina de desarrollo. Pero para separarlos, tienes que poder lanzar cada proyecto de forma independiente; para mí, eso es lo que significa múltiples proyectos . Pero no es una cosa difícil de hacer:

Primero, un proyecto usa elementos externos para hacer referencia a una versión específica lanzada de una biblioteca. Esa es la única forma en que un proyecto hace referencia a una biblioteca. Hacer esto significa que los desarrolladores pueden crear una nueva versión de la biblioteca sin romper ninguno de los proyectos que la usan, porque todos los proyectos harán referencia a la versión anterior. Los proyectos pueden controlar cuándo quieren traer nuevas versiones de bibliotecas: los desarrolladores pueden elegir cuándo quieren poner el esfuerzo de probar su código con la nueva versión y cuándo tomarse la molestia de solucionar cualquier problema de compilación de la nueva biblioteca presenta.

Cuando cambias explícitamente versiones de una biblioteca como esta, también obtienes una entrada en tu proyecto que dice "Ahora estoy usando esta versión de la biblioteca X", que te da una buena idea. sentido de la historia en su proyecto en cuanto a cuándo funcionaban las cosas y exactamente cuándo cambiaron las cosas.

Ahora, por supuesto, todo esto es bueno en teoría, pero en la práctica, los desarrolladores a veces tendrán que hacer referencia a las versiones inestables e inacabadas de una biblioteca. Eso está bien: un desarrollador siempre puede cambiar su copia de trabajo para apuntar al tronco de la biblioteca en lugar de una etiqueta, o alguna rama de desarrollo, y usar el código desde allí (incluso trabajar en ella si es necesario, brrr). Un cambio es solo una edición local, por lo que no tendrá efecto en el código confirmado. Si el desarrollo del proyecto está en una rama inestable, entonces puede decidir hacer que el cambio sea más permanente cambiando la referencia externa hasta que la rama esté lista para ser reintegrada, pero esto no es algo que normalmente se haría sin una razón explícita.

Y, finalmente, la división y etiquetado de su proyecto se convierte en un caso simple de creación de una rama o etiqueta de su proyecto principal, eso es todo. No hay necesidad de preocuparse por la ramificación de las bibliotecas: se cuidan solas. El proceso de hacer un cambio en una biblioteca no cambia si el proyecto está en un tronco, una rama de desarrollo o una versión de mantenimiento. Y sus bibliotecas pueden tener ramas de desarrollo completamente independientes de los proyectos principales, así como múltiples versiones compatibles, etc., hasta el nivel de complejidad que necesite y pueda admitir.

Al usar elementos externos en su troncal o rama de desarrollo, puede tener un solo pago que construye su espacio de trabajo en la estructura que necesite. Debido a que todas las bibliotecas se encuentran en la raíz principal, puede tener múltiples desprotecciones de múltiples versiones sin que se produzcan conflictos en la compilación.

Descubrí que este sistema funciona bastante bien y, después de trasladar los trabajos a un lugar que no funciona de esta manera, me siento ansioso por la forma anterior de trabajar. Hay problemas, principalmente relacionados con las bibliotecas que dependen de las bibliotecas y si deben tener elementos externos recursivos o no. Mi opinión es que es recursivo a menos que cause un problema (o un dolor excesivo), luego pase a un modelo 'degenerado' en el que el proyecto debe conocer ciertas dependencias 'profundas', incluso si no las usa directamente. Además, decida dónde colocará sus definiciones externas y cúmplalas, nada es más molesto que buscar esas svn: propiedades externas en carpetas aleatorias en diferentes proyectos. Ponerlos en la raíz del tronco está bien.

Este es un problema difícil que no tiene una buena solución barata; la solución de gama alta es usar un & # 8220; líneas de productos de software & # 8221; sistema de gestión (p. ej., pure :: variantes ). Sin embargo, la mayoría de nosotros no podemos gastar esa coincidencia en un sistema de control de código fuente.

Por lo tanto, iría con LayoutA & # 8211; con cada biblioteca versionada por separado. Sin embargo, tendería a poner & # 8220; trunk & # 8221; bajo & # 8220; ramas & # 8221; ya que es una rama y me gusta tener todas las ramas a la misma distancia de la parte superior.

El siguiente paso más bien depende de su sistema de compilación, supongo que Visual Studio aquí.

  • En la raíz de cada árbol de rama de producto
  • Cree un archivo bat que defina una variable de entorno que contenga el nombre de la rama de cada biblioteca que desee usar
  • Edite los archivos de proyecto de Visual Studio para hacer referencia a las bibliotecas utilizando estas variables de entorno
  • Ejecute el archivo por lotes desde el símbolo del sistema de Visual Studio antes de iniciar Visual Studio

También podría considerar escribir un archivo MSBuild personalizado en lugar de usar un archivo por lotes. O escribir una herramienta que edite todos los archivos del proyecto cuando cambie la versión de una biblioteca.

Si solo tiene 1 o 2 bibliotecas compartidas y solo se cambian para un producto a la vez, .e.g. para agregar nuevos métodos para el proyecto en el que se está trabajando ahora. Consideraría tener una rama diferente de la biblioteca para cada proyecto, y usar el vikingo de combinación SVN 1.5 para realizar un seguimiento de lo que está sucediendo. (Cuando los cambios son estables, fusione con el camión, luego fusione del camión con cada sucursal de proyectos cuando sea necesario)

(Si tiene cientos de bibliotecas, debe realizar un seguimiento de la versión de cada biblioteca que se necesita. ¡Esto comienza a ser muy complejo!)

No me gusta svn: external, ya que no está claro en el sistema de archivos de su PC local lo que está sucediendo. Sin embargo, svn: external es una solución viable.

Habiendo pasado por un problema similar, conozco tu dolor. Es un problema difícil administrar las dependencias en un repositorio con componentes jerárquicos.

Nuestro proyecto tenía varios productos (independientemente de lo que envíes a los clientes) compuestos de varios componentes (muchos de los cuales se comparten). Tuvimos cada componente con su propia trilogía tags / branch / trunk , muy parecido a su Disposición A (que es, después de todo, la forma recomendada).

Usamos svn: externals para proporcionar una manera para que cada producto especifique componentes dependientes (y subcomponentes, etc.), y al principio funcionó razonablemente bien. Pero finalmente tuvimos problemas, como lo que sucede cuando se ramifica, qué sucede si un producto necesita fijar una dependencia en una revisión determinada, ¿cómo propaga las etiquetas a través de externos para la gestión de la configuración (para que pueda reconstruir el mismo árbol) , y así. Así que svn: externals resuelve algunos problemas pero introduce otros.

Terminé escribiendo algunos scripts para gestionar esto, pero aún estaba un poco complicado. Afortunadamente, puede usar los enlaces de Python-Subversion para escribir aplicaciones de Python para manipular propiedades, por lo que puede hacer cosas como propagar etiquetas a través de componentes dependientes, etc.

Hay un proyecto que está diseñado para abordar este problema de los módulos dependientes, llamado Piston . Parece una herramienta genérica muy buena para exactamente este tipo de problema. No lo implementé en producción, pero en ese momento parecía que haría la mayor parte de lo que necesitamos. Y, ciertamente, parece una solución más flexible que la que ofrecen los externos (que aún es un proceso muy manual).

Conclusión: podría seguir con el Diseño A y usar Piston para administrar las dependencias para que todas las versiones correctas de sus bibliotecas se ensamblen en su directorio de trabajo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top