svn - tortoise - ¿Cómo organizas tu repositorio de control de versiones?
svn branches tags trunk (8)
Primero, sé de esto: ¿cómo organizarías un repositorio de Subversion para proyectos de software internos? A continuación, la pregunta real: mi equipo está reestructurando nuestro repositorio y estoy buscando pistas sobre cómo organizarlo. (SVN en este caso). Esto es lo que se nos ocurrió. Tenemos un repositorio, proyectos múltiples y múltiples referencias cruzadas de svn: externals
/commonTools /*tools used in all projects. Referenced in each project with svn:externals*/
/NUnit.v2.4.8
/NCover.v.1.5.8
/<other similar tools>
/commonFiles /*settings strong name keys etc.*/
/ReSharper.settings
/VisualStudio.settings
/trash /*each member of the team has trash for samples, experiments etc*/
/user1
/user2
/projects
/Solution1 /*Single actual project (Visual Studio Solution)*/
/trunk
/src
/Project1 /*Each sub-project resulting in single .dll or .exe*/
/Project2
/lib
/tools
/tests
/Solution1.sln
/tags
/branches
/Solution2
/trunk
/src
/Project3 /*Each sub-project resulting in single .dll or .exe*/
/Project1 /*Project1 from Solution1 references with svn:externals*/
/lib
/tools
/tests
/Solution2.sln
/tags
/branches
Para borrar el vocabulario: Solution significa producto único, Project es un proyecto de Visual Studio (que da como resultado un solo .dll o un solo .exe)
Así es como planeamos diseñar el repositorio. El problema principal es que tenemos múltiples soluciones, pero queremos compartir proyectos entre soluciones. Pensamos que realmente no tiene sentido trasladar esos proyectos compartidos a sus propias soluciones y, en su lugar, decidimos usar svn: externals para compartir proyectos entre soluciones. También queremos mantener un conjunto común de herramientas y bibliotecas de terceros en un lugar del repositorio, y hacer referencia a ellas en cada solución con svn: external.
¿Qué piensas de este diseño? Especialmente sobre el uso de svn: externals. No es una solución ideal, pero considerando todos los pros y los contras, es lo mejor que se nos ocurre. ¿Como lo harias?
¿Por qué tener todo en un repositorio? ¿Por qué no tener un repositorio separado para cada proyecto (me refiero a "Solución")?
Bueno, al menos estoy acostumbrado al enfoque de un proyecto por repositorio. Tu estructura de repositorio me parece demasiado complicada.
¿Y cuántos proyectos planea poner en este gran repositorio? 2? 3? 10? 100?
¿Y qué haces cuando cancelas el desarrollo de un proyecto? Simplemente elimínelo del árbol de repositorio para que sea difícil de encontrar en el futuro. ¿O dejarlo por siempre? ¿O cuando quieres mover un proyecto a otro servidor por completo?
¿Y el desorden de todos esos números de versión? Los números de versión de un proyecto van como 2, 10, 11, mientras que el otro va como 1, 3, 4, 5, 6, 7, 8, 9, 12 ...
Tal vez soy tonto, pero me gusta un proyecto por repositorio.
Creo que Pragmatic Version Control con Subversion tiene todo lo que necesita para organizar su repositorio.
Creo que la principal desventaja de la estructura propuesta es que los proyectos compartidos solo se versionarán con la primera solución a la que se agregaron (a menos que svn: externals sea más elegante de lo que imagino). Por ejemplo, cuando crea una rama para la primera versión de Solution2, Project1 no se ramificará, ya que vive en Solution1. Si necesita construir desde esa rama en un momento posterior (versión QFE), usará la última versión de Project1 en lugar de la versión de Project1 en el momento de la sucursal.
Por esta razón, puede ser ventajoso colocar los proyectos compartidos en una o más soluciones compartidas (y, por lo tanto, directorios de nivel superior en su estructura) y luego bifurcarlos con cada versión de cualquier solución.
Hemos configurado el nuestro para que coincida casi exactamente con lo que ha publicado. Usamos la forma general:
/Project1
/Development (for active dev - what you''ve called "Trunk", containing everything about a project)
/Branches (For older, still-evolving supported branches of the code)
/Version1
/Version1.1
/Version2
/Documentation (For any accompanying documents that aren''t version-specific
Si bien supongo que no es tan completo como su ejemplo, nos funcionó bien y nos permite mantener las cosas separadas. También me gusta la idea de que cada usuario tenga una carpeta "Thrash"; actualmente, esos tipos de proyectos no terminan en el control de Source, y siempre he pensado que deberían hacerlo.
Para agregar al tema de la ruta relativa:
No estoy seguro de que sea un problema:
Simplemente descargue Solution1 / trunk bajo el directorio llamado "Solution1", ídem para Solution2: el objetivo de los "directorios" que realmente representan las sucursales es no ser visibles una vez importados en un área de trabajo. Por lo tanto, las rutas relativas son posibles entre ''Solution1'' (en realidad ''Solution1 / trunk'') y ''Solution2'' (Solution2 / trunk).
RE: la ruta relativa y el problema del archivo compartido -
Parece que esto es svn específico, pero eso no es un problema. Otra persona ya mencionó repositorios separados y esa es probablemente la mejor solución que puedo pensar en el caso en que tenga proyectos diferentes que se refieran a otros proyectos arbitrarios. En el caso de que no tenga archivos compartidos, la solución de OP (así como muchos otros) funcionará bien.
Todavía estamos trabajando en esto y tengo 3 esfuerzos diferentes (clientes diferentes) que tengo que resolver en este momento desde que asumí la configuración de control de versión inexistente o deficiente.
Si sigues mis recomendaciones a continuación (tengo durante años), serás capaz de:
- ponga cada proyecto en cualquier lugar en control de fuente, siempre y cuando preserve la estructura desde el directorio raíz del proyecto hacia abajo
- construir cada proyecto en cualquier lugar y en cualquier máquina, con un riesgo mínimo y una preparación mínima
- construye cada proyecto completamente independiente, siempre y cuando tengas acceso a sus dependencias binarias (directorios locales "biblioteca" y "salida")
- construir y trabajar con cualquier combinación de proyectos, ya que son independientes
- construir y trabajar con copias múltiples / versiones de un solo proyecto, ya que son independientes
- Evite saturar el repositorio de control de origen con archivos o bibliotecas generados
Recomiendo (aquí está la carne):
Defina cada proyecto para producir un entregable principal único, como .DLL, .EXE o .JAR (predeterminado con Visual Studio).
Estructure cada proyecto como un árbol de directorios con una sola raíz.
Cree un script de compilación automatizado para cada proyecto en su directorio raíz que lo compilará desde cero, sin dependencias en un IDE (pero no impida que se construya en el IDE, si es posible).
Considere nAnt para proyectos .NET en Windows, o algo similar basado en su sistema operativo, plataforma de destino, etc.
Haga que cada referencia de script de compilación de proyecto sea externa (de terceros) dependencias de un solo directorio de "biblioteca" compartido local, con cada binario identificado TOTALMENTE por la versión:
%DirLibraryRoot%/ComponentA-1.2.3.4.dll
,%DirLibraryRoot%/ComponentB-5.6.7.8.dll
.Haga que cada script de compilación de proyecto publique el entregable principal en un solo directorio de "salida" compartido local:
%DirOutputRoot%/ProjectA-9.10.11.12.dll
,%DirOutputRoot%/ProjectB-13.14.15.16.exe
.Haga que cada referencia de script de compilación de proyecto dependa de las rutas absolutas configurables y totalmente versionadas (consulte más arriba) en los directorios "biblioteca" y "salida", Y NO EN DONDE.
NUNCA deje que un proyecto haga referencia directamente a otro proyecto o cualquiera de sus contenidos, solo permita referencias a los entregables principales en el directorio de "salida" (vea arriba).
Haga que cada referencia de script de compilación de proyecto sea una de las herramientas de compilación necesarias mediante una ruta absoluta configurable y completamente versionada:
%DirToolRoot%/ToolA/1.2.3.4
,%DirToolRoot%/ToolB/5.6.7.8
.Haga que cada proyecto compile el contenido fuente de referencia mediante una ruta absoluta relativa al directorio raíz del proyecto:
${project.base.dir}/src
,${project.base.dir}/tst
(la sintaxis varía según la herramienta de compilación).SIEMPRE requiere un script de compilación de proyecto para hacer referencia a CADA archivo o directorio a través de una ruta absoluta configurable (enraizada en un directorio especificado por una variable configurable):
${project.base.dir}/some/dirs
o${env.Variable}/other/dir
.NUNCA permita que un script de compilación de proyecto haga referencia a NADA con una ruta relativa como
./some/dirs/here
o../some/more/dirs
, SIEMPRE use rutas absolutas.NUNCA permita que un script de compilación de proyecto haga referencia a NADA utilizando una ruta absoluta que no tenga un directorio raíz configurable, como
C:/some/dirs/here
o//server/share/more/stuff/there
.Para cada directorio raíz configurable al que hace referencia un script de compilación de proyecto, defina una variable de entorno que se usará para esas referencias.
Intente minimizar el número de variables de entorno que debe crear para configurar cada máquina.
En cada máquina, cree un script de shell que defina las variables de entorno necesarias, que son específicas de esa máquina (y posiblemente específicas de ese usuario, si corresponde).
NO coloque el script de shell de configuración específico de la máquina en el control de fuente; en su lugar, para cada proyecto, envíe una copia del script en el directorio raíz del proyecto como plantilla.
REQUIERA que cada script de construcción del proyecto verifique cada una de sus variables de entorno, y aborten con un mensaje significativo si no están definidas.
REQUIERA que cada script de compilación de proyecto verifique cada uno de sus ejecutables de herramienta de compilación dependientes, archivos de biblioteca externa y archivos entregables de proyecto dependientes, y cancele con un mensaje significativo si esos archivos no existen.
RESISTE la tentación de enviar CUALQUIER archivo generado al control de código fuente, sin entregables del proyecto, sin fuente generada, sin documentos generados, etc.
Si usa un IDE, genere los archivos de control de proyecto que pueda y no los comprometa con el control de origen (esto incluye los archivos de proyecto de Visual Studio).
Establezca un servidor con una copia oficial de todas las bibliotecas y herramientas externas, para ser copiado / instalado en estaciones de trabajo de desarrollador y máquinas de construcción. Haga una copia de seguridad, junto con su repositorio de control de origen.
Establezca un servidor de integración continua (máquina de creación) sin herramientas de desarrollo en absoluto.
Considere una herramienta para administrar sus bibliotecas externas y entregables, como Ivy (utilizado con Ant).
NO uses Maven: inicialmente te hará feliz y finalmente te hará llorar.
Tenga en cuenta que nada de esto es específico de Subversion, y la mayor parte es genérica para proyectos dirigidos a cualquier sistema operativo, hardware, plataforma, idioma, etc. Utilicé un poco de sintaxis específica del sistema operativo y de la herramienta, pero solo para ilustración. Confío en que traducirá a su sistema operativo o herramienta de elección.
Nota adicional sobre las soluciones de Visual Studio: ¡no las ponga en control de fuente! Con este enfoque, no los necesita en absoluto o puede generarlos (al igual que los archivos de proyecto de Visual Studio). Sin embargo, considero que es mejor dejar los archivos de la solución a desarrolladores individuales para que los creen / usen como mejor les parezcan (pero no se verifiquen en el control de la fuente). Rob.sln
un archivo Rob.sln
en mi estación de trabajo desde el cual hago referencia a mis proyectos actuales. Como mis proyectos son independientes, puedo agregar / eliminar proyectos a voluntad (eso significa que no hay referencias de dependencia basadas en proyectos).
No utilice Subversion externos (o similares en otras herramientas), son un antipatrón y, por lo tanto, innecesarios.
Cuando implemente la integración continua, o incluso cuando solo desee automatizar el proceso de lanzamiento, cree un script para él. Cree un único script de shell que: tome los parámetros del nombre del proyecto (como figura en el repositorio) y el nombre de la etiqueta, cree un directorio temporal dentro de un directorio raíz configurable, compruebe el origen del nombre del proyecto y el nombre de la etiqueta (construyendo el URL apropiada en el caso de Subversion) a ese directorio temporal, realiza una compilación limpia que ejecuta pruebas y empaqueta el entregable. Este script de shell debería funcionar en cualquier proyecto y se debe verificar en el control de código fuente como parte de su proyecto de "herramientas de compilación". Su servidor de integración continua puede usar este script como base para la creación de proyectos, o incluso podría proporcionarlo (pero aún puede querer el suyo).
@VonC: NO quieres trabajar en todo momento con "ant.jar" en lugar de "ant-abcdjar" después de quemarte cuando se rompe tu script de compilación porque lo ejecutaste sin saberlo con una versión incompatible de Ant. Esto es particularmente común entre Ant 1.6.5 y 1.7.0. Generalizando, SIEMPRE desea saber qué versión específica de CADA componente se está utilizando, incluida su plataforma (Java ABCD) y su herramienta de construcción (Ant EFGH). De lo contrario, eventualmente encontrará un error y su primer gran problema será rastrear qué versiones de sus diversos componentes están involucradas. Simplemente es mejor resolver ese problema por adelantado.
Tengo un diseño similar, pero mi tronco, ramas, etiquetas todo el camino en la parte superior. Entonces: / trunk / main, / trunk / utils, / branches / release /, etc.
Esto terminó siendo muy útil cuando queríamos probar otros sistemas de control de versiones porque muchas de las herramientas de traducción funcionaban mejor con el diseño SVN básico de los libros de texto.