Diseño del Repositorio Subversion


La mayoría de las herramientas de subversion crean un diseño de repositorio predeterminado con /trunk, /branches y /tags. La documentación también recomienda no usar repositorios separados para cada proyecto, para que el código pueda compartirse más fácilmente.

Siguiendo ese consejo me ha llevado a tener un repositorio con el siguiente diseño:

/trunk
      /Project1
      /Project2
/branches
         /Project1
         /Project2
/tags
     /Project1
     /Project2

Y así sucesivamente, usted consigue la idea. Con el tiempo, he encontrado esta estructura un poco torpe y se me ocurrió que hay una interpretación alternativa de la recomendaciones, tales como:

/Project1
         /trunk
         /branches
         /tags
/Project2
         /trunk
         /branches
         /tags       

Entonces, ¿qué diseño usan las personas y por qué? O - ¿hay otra manera de hacer las cosas que me he perdido por completo?

Author: Kevin Reid, 2010-04-10

6 answers

Encuentro que la publicación del blog Diseño del repositorio Subversion resume esto bastante bien:

(...) hay varios diseños comunes que han sido adoptadas por el la comunidad como mejores prácticas y por lo tanto, uno podría pensar en estos como recomendaciones. Si su repositorio es accesible al público, siguiendo estas convenciones podrían hacerlo más fácil para los usuarios que han accedido a otros Repositorios de Subversion para encontrar lo que están buscando.

Hay dos diseños comúnmente utilizados:

trunk
branches
tags

Este primer diseño es la mejor opción para un repositorio que contiene un proyecto único o conjunto de proyectos que están estrechamente relacionados con cada los demás. Este diseño es útil porque es simple ramificar o etiquetar el proyecto completo o conjunto de proyectos con un solo comando:

svn copy url://repos/trunk url://repos/tags/tagname -m "Create tagname"

Este es probablemente el más común diseño de repositorio usado y es utilizado por muchos proyectos de código abierto, como Subversion y Subclipse. Este es el diseño que la mayoría de los sitios de alojamiento like Tigris.org, SourceForge.net y Google Code seguir como cada proyecto en estos sitios se da su propio repositorio.

El siguiente diseño es la mejor opción para un repositorio que contiene no relacionados o proyectos poco relacionados .

ProjectA
   trunk
   branches
   tags
ProjectB
   trunk
   branches
   tags

En este diseño, cada proyecto recibe una carpeta de nivel superior y luego el las carpetas trunk/branches/tags son creado debajo de él. Esto es realmente el mismo diseño que el primer diseño, es solo que en lugar de poner cada proyecto en su propio repositorio, ellos están todos en un único repositorio. El Apache Software Foundation utiliza este diseño para su repositorio que contiene todos sus proyectos en uno repositorio único.

Con este diseño, cada proyecto tiene su propias ramas y etiquetas y es fácil para crear los archivos que proyecto usando un comando, similar a el anterior muestra:

svn copy url://repos/ProjectA/trunk url://repos/ProjectA/tags/tagname -m "Create tagname"

Lo que no se puede hacer fácilmente en este layout es crear una rama o etiqueta que contiene archivos de ProjectA y Proyectob. Todavía puedes hacerlo, pero requiere múltiples comandos y también tienes que decidir si vas para hacer una carpeta especial para el ramas y etiquetas que involucran múltiples proyectos. Si vas a necesita hacer esto mucho, es posible que desee para considerar el primer diseño.

Así, a paráfrasis:

  • Utilice el primer diseño para uno o varios proyectos relacionados.
  • Utilice el segundo diseño para proyectos no relacionados.

Vale la pena leer todo el post.

 31
Author: Pascal Thivent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-28 01:44:52

El segundo diseño es el camino a seguir. Una buena razón es permitir o negar a un desarrollador trabajar con uno de los proyectos.

 8
Author: David Espart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-09 22:06:43

Prefiero el segundo. Con el segundo, si los permisos de las personas son diferentes entre los dos proyectos, es más fácil de implementar.

 5
Author: Andrew B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-09 22:06:01

Prefiero el segundo, usando maven o ant/ivy para ingerir los artefactos de otros proyectos si es necesario.

También prefiero tener un solo proyecto por repositorio, o un pequeño número de repositorios relacionados.

Simplifica el control de acceso, que es más fácil a nivel de repositorio que el nivel de ruta dentro del repositorio, particularmente cuando se autentica contra LDAP.

Las operaciones de copia de seguridad/restauración son un poco más complicadas inicialmente, ya que tiene que repetir a través de todos los repositorios para hacer una copia en caliente, pero en el desafortunado evento que tiene que restaurar solo un repositorio - los demás no necesitan ser tomados fuera de línea o perder ningún dato. A medida que los proyectos mueren, los repositorios simplemente se pueden eliminar, lo que le ahorra espacio en copias de seguridad futuras.

Los scripts de Hook se vuelven más simples cuando solo hay un proyecto (o un pequeño número de proyectos relacionados) por repositorio, no tiene que examinar la ruta afectada para tomar medidas condicionalmente en su hook.

Como retráctil cabe señalar que un repositorio monolítico es probable que sea un gran dolor si alguna vez desea exportar selectivamente utilizando svndumpfilter - el número de rutas cambiadas que causan que muera es probable que sea alto.

Actualizar el esquema de repositorio para futuras versiones de svn requiere más esfuerzo - debe hacerlo n veces en lugar de una vez... pero se puede programar y no es necesario coordinar a todos a la vez.

Si alguien confirma una contraseña, y tienes que borrarla, puedes hacer el volcado / filtro / recarga rápidamente en un repositorio sin afectar a otros equipos.

Un consejo si vas por este camino - tener una diferente .conf file per repo en lugar de uno enorme, una vez más es más fácil de administrar, así como proporcionar comodidad de que algunas marcas de tiempo van a ser viejas - si algo está mal, puede buscar cambios recientes más fácil.

 2
Author: thekbb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-05 15:28:56

Decidí morder el anzuelo y reestructurar mi repositorio. Escribí un pequeño programa para ayudar (abajo). Los pasos que seguí fueron:

  1. Haga una copia de seguridad del repositorio original.
  2. svn checkout todo el repositorio . Esto tomó mucho tiempo y mucho espacio en disco.
  3. Ejecute el programa desde abajo en la copia de trabajo del paso anterior.
  4. Examinar la copia de trabajo modificada y ordenar cualquier problema sobrante (por ejemplo. svn delete el obsoleto tronco, etiquetas y ramas carpetas)
  5. svn commit de vuelta al repositorio.

Todo este proceso tomó tiempo, pero decidí tomar este enfoque porque modificar una copia de trabajo es mucho más seguro que hackear un repositorio en vivo y tenía las opciones de simplemente tirar la copia de trabajo si todo salió mal, para solucionar cualquier problema en la copia de trabajo y confirmar toda la reestructuración como una sola revisión.

Aquí está el código C# que usé para hacer el movimiento. Requiere biblioteca SharpSvn.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using SharpSvn;

/**
 * 
 * Program operation:
 * 1. Parse command line to determine path to working copy root
 * 2. Enumerate folders in the /trunk 
 * 3. Restructure each project folder in /trunk
 * 
 * 
 * Restructure a Project:
 * 1. Get the project name (folder name in /trunk/{Project})
 * 2. SVN Move /trunk/{Project} to /{Project}/trunk
 * 3. Reparent Project, branches
 * 4. Reparent Project, tags
 * 
 * Reparent(project, folder)
 * If /{folder}/{Project} exists
 *   SVN Move /{folder}/{Project} to /{Project}/{Folder}
 * else
 *   Create folder /{Project}/{Folder}
 *   SVN Add /{Project}/{Folder}
 * 
 **/

namespace TiGra.SvnRestructure
{
    /// <summary>
    /// Restructures a Subversion repository from
    ///     /trunk|branches|tags/Project
    /// to
    ///     /Project/trunk|branches|tags
    /// </summary>
    internal class Program
    {
        private static string WorkingCopy;
        private static string SvnUri;
        private static string Branches;
        private static string Tags;
        private static string Trunk;

        private static SvnClient svn;
        private static List<string> Projects;

        private static void Main(string[] args)
        {
            ProcessCommandLine(args);
            CreateSvnClient();
            EnumerateProjectsInTrunk();
            RestructureProjects();
            Console.ReadLine();
        }

        private static void RestructureProjects()
        {
            foreach (var project in Projects)
            {
                RestructureSingleProject(project);
            }
        }

        private static void RestructureSingleProject(string projectPath)
        {
            var projectName = Path.GetFileName(projectPath);
            var projectNewRoot = Path.Combine(WorkingCopy, projectName);
            bool hasBranches = Directory.Exists(Path.Combine(Branches, projectName));
            bool hasTags = Directory.Exists(Path.Combine(Tags, projectName));
            Reparent(Path.Combine(Trunk, projectName), Path.Combine(projectNewRoot, "trunk"));
            if (hasBranches)
                Reparent(Path.Combine(Branches, projectName), Path.Combine(projectNewRoot, "branches"));
            if (hasTags)
                Reparent(Path.Combine(Tags, projectName), Path.Combine(projectNewRoot, "tags"));
        }

        private static void Reparent(string oldPath, string newPath)
        {
            Console.WriteLine(string.Format("Moving {0} --> {1}", oldPath, newPath));
            svn.Move(oldPath, newPath, new SvnMoveArgs(){CreateParents = true});
        }

        private static void EnumerateProjectsInTrunk()
        {
            var list = EnumerateFolders("trunk");
            Projects = list;
        }

        /// <summary>
        /// Enumerates the folders in the specified subdirectory.
        /// </summary>
        /// <param name="trunk">The trunk.</param>
        private static List<string> EnumerateFolders(string root)
        {
            var fullPath = Path.Combine(WorkingCopy, root);
            var folders = Directory.GetDirectories(fullPath, "*.*", SearchOption.TopDirectoryOnly).ToList();
            folders.RemoveAll(s => s.EndsWith(".svn")); // Remove special metadata folders.
            return folders;
        }

        private static void CreateSvnClient()
        {
            svn = new SharpSvn.SvnClient();
        }

        /// <summary>
        /// Processes the command line. There should be exactly one argument,
        /// which is the path to the working copy.
        /// </summary>
        private static void ProcessCommandLine(string[] args)
        {
            if (args.Length != 1)
                throw new ArgumentException("There must be exactly one argument");
            var path = args[0];
            if (!Directory.Exists(path))
                throw new ArgumentException("The specified working copy root could not be found.");
            WorkingCopy = path;
            Branches = Path.Combine(WorkingCopy, "branches");
            Tags = Path.Combine(WorkingCopy, "tags");
            Trunk = Path.Combine(WorkingCopy, "trunk");
        }
    }
}
 1
Author: Tim Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-21 21:05:47

Consulte Disposición del repositorio desde el svnbook

Hay algunas formas estándar y recomendadas de organizar el contenido de repositorio. La mayoría de la gente crea un directorio troncal para contener el " main línea " de desarrollo, un directorio de ramas para contener copias de ramas, y un directorio de etiquetas para contener copias de etiquetas.

/
   trunk/
   branches/
   tags/

Si un repositorio contiene varios proyectos, los administradores normalmente indexan su diseño por proyecto.

Aquí hay un ejemplo de tal diseño:

/
   paint/
      trunk/
      branches/
      tags/
   calc/
      trunk/
      branches/
      tags/

Por supuesto, eres libre de ignorar estos diseños comunes. Puede crear cualquier tipo de variación, lo que funcione mejor para usted o su equipo. Recuerda que lo que elijas, no es un compromiso permanente. Puede reorganizar su repositorio en cualquier momento. Porque ramas y las etiquetas son directorios ordinarios, el comando svn move puede mover o renombrar ellos como quieras. Cambiar de un diseño a otro es solo un cuestión de emitir una serie de servidores se mueve; si no te gusta el la forma en que las cosas están organizadas en el repositorio, directorios alrededor.

Recuerde, sin embargo, que mientras mover directorios es fácil de hacer, usted necesidad de ser considerado con otros usuarios también. Tu malabarismo puede desorientar a los usuarios con las copias de trabajo existentes. Si un usuario tiene un trabajo copia de un directorio de repositorio en particular y su subcomando svn move elimina la ruta de la última revisión, luego cuando el usuario siguiente ejecuta svn update, ella se le dice que su copia de trabajo representa un camino eso ya no existe. Luego se ve obligada a cambiar svn a la nueva ubicación.

 0
Author: Lucky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-18 11:18:36