Макет хранилища Subversion - PullRequest
       32

Макет хранилища Subversion

31 голосов
/ 10 апреля 2010

Большинство инструментов subversion создают макет хранилища по умолчанию с помощью / trunk, / branch и / tags. В документации также рекомендуется не использовать отдельные репозитории для каждого проекта, чтобы было проще делиться кодом.

Следуя этому совету, я получил хранилище со следующим макетом:

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

и так далее, вы поняли идею. Со временем я нашел эту структуру немного неуклюжей, и мне пришло в голову, что есть альтернативное толкование рекомендаций, например:

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

Итак, какой макет используют люди и почему? Или - есть ли другой способ сделать то, что я полностью пропустил?

Ответы [ 6 ]

32 голосов
/ 10 апреля 2010

Я обнаружил, что пост блога Subversion Repository в блоге обобщает это довольно хорошо:

(...) Есть несколько распространенных макетов которые были приняты сообщество как лучшие практики и поэтому можно думать о них как рекомендации. Если ваш репозиторий доступны для общественности, следуя эти соглашения могут облегчить для пользователей, которые обращались к другим Subversion репозитории, чтобы найти то, что они ищут.

Существует два часто используемых макета:

trunk
branches
tags

Этот первый макет является лучшим вариантом для хранилища, которое содержит один проект или набор проектов которые тесно связаны с каждым другой . Этот макет полезен, потому что это просто разветвить или пометить весь проект или набор проектов с помощью одной команды:

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

Это, пожалуй, наиболее часто используется макет хранилища и используется многие проекты с открытым исходным кодом, как Сама Subversion и Subclipse. это это макет, который большинство сайтов хостинга как Tigris.org, SourceForge.net и Код Google следует за каждым проектом в этим сайтам дан свой хранилище.

Следующий макет - лучший вариант для хранилище, которое содержит не связанные или слабо связанные проекты .

ProjectA
   trunk
   branches
   tags
ProjectB
   trunk
   branches
   tags

В этом макете каждый проект получает папка верхнего уровня, а затем папки ствола / ветви / теги создан под ним. Это действительно тот же макет, что и первый макет, это просто вместо того, чтобы ставить каждый проект в своем собственном хранилище, они все в одном хранилище. Apache Software Foundation использует это макет для их хранилища, которое содержит все свои проекты в одном один репозиторий.

При таком макете каждый проект имеет собственные ветки и метки и это легко чтобы создать их для файлов в этом проект с использованием одной команды, аналогичной ранее показанный:

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

Что вы не можете легко сделать в этом макет создать ветку или тег, который содержит файлы из ProjectA и ProjectB. Вы все еще можете сделать это, но это требует нескольких команд и вы также нужно решить, собираетесь ли вы сделать специальную папку для ветви и теги, которые включают несколько проектов. Если вы собираетесь нужно сделать это много, вы можете захотеть рассмотреть первый макет.

Итак, перефразируя:

  • Используйте первый макет для одного или нескольких связанных проектов.
  • Используйте второй макет для не связанных проектов.

Весь пост стоит прочитать.

8 голосов
/ 10 апреля 2010

Второй макет это путь. Хорошая причина - разрешить или запретить разработчику работать с одним из проектов.

5 голосов
/ 10 апреля 2010

Я предпочитаю второе. Со вторым, если права доступа людей отличаются между двумя проектами, это легче реализовать.

2 голосов
/ 05 мая 2011

Я предпочитаю второе, используя maven или ant / ivy, чтобы при необходимости использовать артефакты из других проектов.

Я также предпочитаю иметь один проект на репозиторий или небольшое количество связанных репозиториев.

Это упрощает управление доступом, что проще на уровне хранилища, чем на уровне пути внутри хранилища, особенно при проверке подлинности с использованием LDAP.

Операции резервного копирования / восстановления изначально немного сложнее, так как вам нужно циклически пройти по всем репозиториям, чтобы сделать горячее копирование, но в случае неудачи вам нужно восстановить только один репозиторий - остальные не нужно переводить в автономный режим или потерять любые данные. Когда проекты умирают, репозитории могут быть просто удалены, что экономит ваше место на будущих резервных копиях.

Сценарии хуков становятся проще, когда в репозитории имеется только один проект (или небольшое количество связанных проектов), и вам не нужно изучать уязвимый путь, чтобы условно выполнить действие в вашем хуке.

Как отмечалось в retracile, один монолитный репозиторий, вероятно, будет огромной болью, если вы когда-нибудь захотите выборочно экспортировать, используя svndumpfilter - число измененных путей, вызывающих его гибель, вероятно, будет высоким.

Обновление схемы репозитория для будущих версий svn требует больше усилий - вы должны делать это n раз, а не один раз ... но это может быть записано в сценарии, и вам не нужно координировать все сразу.

Если кто-то фиксирует пароль, и вам необходимо его стереть, вы можете быстро выполнить дамп / фильтр / перезагрузку за один репо, не затрагивая другие команды.

Один совет, если вы идете по этому пути - используйте другой файл .conf для репо, а не один огромный, опять же, им проще управлять, а также удобнее, если некоторые временные метки будут старыми - если что-то вас не устраивает проще искать последние изменения.

1 голос
/ 22 августа 2011

Я решил укусить пулю и реструктурировать свой репозиторий. Я написал небольшую программу для оказания помощи (ниже). Шаги, которые я выполнил, были:

  1. Сделайте резервную копию исходного хранилища.
  2. svn checkout весь репозиторий . Это заняло много времени и много места на диске.
  3. Запустите программу снизу на рабочей копии с предыдущего шага.
  4. Изучите измененную рабочую копию и исправьте все оставшиеся проблемы (например, svn delete устаревшие транк , теги и ветви папки)
  5. svn commit обратно в хранилище.

Весь этот процесс занял время, но я решил использовать этот подход, потому что изменение рабочей копии намного безопаснее, чем взлом живого репозитория, и у меня были варианты просто выбросить рабочую копию, если все пошло не так, исправьте любую проблему в рабочей копии и передайте всю реструктуризацию как единую ревизию.

Вот код C #, который я использовал для перемещения. Требуется библиотека 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");
        }
    }
}
0 голосов
/ 18 ноября 2017

См. Макет репозитория из svnbook

Существует несколько стандартных, рекомендуемых способов организации содержимого хранилище. Большинство людей создают магистральный каталог для хранения «основного линия »развития, каталог веток, содержащий копии веток, и каталог тегов, содержащий копии тегов.

/
   trunk/
   branches/
   tags/

Если репозиторий содержит несколько проектов, администраторы обычно индексируют их макет по проекту.

Вот пример такой раскладки:

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

Конечно, вы можете игнорировать эти распространенные макеты. Вы можете создать любые изменения, которые лучше всего подходят для вас или вашей команды. Помните, что что бы вы ни выбрали, это не постоянное обязательство. Вы можете реорганизовать свой репозиторий в любое время. Потому что ветви и теги - это обычные каталоги, команда svn move может перемещать или переименовывать их, как вы хотите. Переключение с одного макета на другой - это просто вопрос выпуска ряда ходов на стороне сервера; если вам не нравится как все организовано в хранилище, просто жонглируйте каталоги вокруг.

Помните, что, хотя перемещение каталогов легко сделать, вы нужно быть внимательным и к другим пользователям. Ваша жонглирование дезориентированные пользователи с существующими рабочими копиями. Если у пользователя есть рабочий копия конкретного каталога репозитория и вашей подкоманды svn move удаляет путь из последней ревизии, затем, когда пользователь следующий запускает обновление SVN, ей говорят, что ее рабочая копия представляет путь этого больше не существует. Затем она вынуждена свн перейти на новый место.

...