ほとんどのSubversionツールは、/ trunk、/ branchs、および/ tagsを使用してデフォルトのリポジトリレイアウトを作成します。また、ドキュメントでは、コードをより簡単に共有できるように、プロジェクトごとに個別のリポジトリを使用しないことを推奨しています。
そのアドバイスに従うと、次のレイアウトのリポジトリができました。
/trunk /Project1 /Project2 /branchs /Project1 /Project2 /tags /Project1 /Project2
などなど、あなたはアイデアを得る。時間が経つにつれて、この構造は少し不器用であることがわかり、次のような推奨事項の別の解釈があることに気付きました。
[.________________ .____。]/tags
では、人々はどのレイアウトを使用しますか、そしてその理由は何ですか?または-私が完全に見逃したことを行う別の方法はありますか?
私は弾丸をかみ、リポジトリを再構築することにしました。私は支援するための小さなプログラムを書きました(以下)。私が従った手順は次のとおりです。
svn checkout
リポジトリ全体。これには長い時間と多くのディスク容量が必要でした。svn delete
廃止されたトランク、タグおよびブランチフォルダー)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");
}
}
}
Subversionリポジトリのレイアウト ブログ投稿はこれをかなりうまく要約していることがわかりました:
(...)コミュニティによってベストプラクティスとして採用されている一般的なレイアウトがいくつかあるため、これらは推奨事項と考えることができます。リポジトリが一般にアクセス可能である場合、これらの規則に従うと、他のSubversionリポジトリにアクセスしたユーザーが探しているものを見つけやすくなる可能性があります。
一般的に使用されるレイアウトは2つあります。
trunk branches tags
この最初のレイアウトは、互いに密接に関連している単一のプロジェクトまたはプロジェクトのセットを含むリポジトリに最適なオプションです。このレイアウトは、プロジェクト全体またはプロジェクトのセットを1つのコマンドで簡単に分岐またはタグ付けできるため便利です。
svn copy url://repos/trunk url://repos/tags/tagname -m "Create tagname"
これはおそらく最も一般的に使用されるリポジトリレイアウトであり、Subversion自体やSubclipseなどの多くのオープンソースプロジェクトで使用されています。これは、Tigris.org、SourceForge.net、Google Codeなどのほとんどのホスティングサイトが、これらのサイトの各プロジェクトに独自のリポジトリが与えられているときに従うレイアウトです。
次のレイアウトは、関連のないプロジェクトまたは関連の緩いプロジェクトを含むリポジトリに最適なオプションです。
ProjectA trunk branches tags ProjectB trunk branches tags
このレイアウトでは、各プロジェクトが最上位フォルダーを受け取り、その下にトランク/ブランチ/タグフォルダーが作成されます。これは実際には最初のレイアウトと同じレイアウトです。各プロジェクトを独自のリポジトリに配置するのではなく、すべて単一のリポジトリに配置するだけです。 Apache Software Foundationは、すべてのプロジェクトを1つのリポジトリーに含むリポジトリーにこのレイアウトを使用します。
このレイアウトでは、各プロジェクトに独自のブランチとタグがあり、前に示したものと同様に、1つのコマンドを使用してそのプロジェクト内のファイル用にそれらを簡単に作成できます。
svn copy url://repos/ProjectA/trunk url://repos/ProjectA/tags/tagname -m "Create tagname"
このレイアウトでは簡単に実行できないのは、ProjectAとProjectBの両方のファイルを含むブランチまたはタグを作成することです。それでも実行できますが、複数のコマンドが必要であり、複数のプロジェクトを含むブランチとタグ用の特別なフォルダーを作成するかどうかも決定する必要があります。これを頻繁に行う必要がある場合は、最初のレイアウトを検討することをお勧めします。
つまり、言い換えると:
投稿全体を読む価値があります。
2番目のレイアウトは進むべき道です。正当な理由の1つは、開発者がプロジェクトの1つで作業することを許可または拒否することです。
私は2番目が好きです。 2つ目は、2つのプロジェクト間でユーザーの権限が異なる場合、実装が簡単です。
必要に応じて、mavenまたはant/ivyを使用して他のプロジェクトからアーティファクトを取り込む、2番目の方法を強くお勧めします。
また、リポジトリごとに1つのプロジェクト、または少数の関連するリポジトリを使用することも好みます。
これにより、アクセス制御が簡素化されます。これは、特にLDAPに対して認証する場合に、リポジトリ内のパスレベルよりもリポジトリレベルで簡単です。
ホットコピーを実行するにはすべてのリポジトリをループする必要があるため、バックアップ/復元操作は最初は少し複雑ですが、不幸な場合は1つのリポジトリのみを復元する必要があります。他のリポジトリをオフラインにしたり、データを失う必要はありません。 。プロジェクトが終了すると、リポジトリを簡単に削除できるため、将来のバックアップのスペースを節約できます。
リポジトリごとにプロジェクトが1つ(または関連するプロジェクトの数が少ない)しかない場合、フックスクリプトはより単純になります。フックで条件付きでアクションを実行するために、影響を受けるパスを調べる必要はありません。
Retracileが指摘したように、svndumpfilterを使用して選択的にエクスポートしたい場合、1つのモノリシックリポジトリは非常に苦痛になる可能性があります。変更されたパスの数が多くなる可能性があります。
Svnの将来のバージョンのためにリポジトリスキーマをアップグレードするには、より多くの労力が必要です-一度ではなくn回...しかし、スクリプト化することができ、全員を一度に調整する必要はありません。
誰かがパスワードをコミットし、それを消去する必要がある場合、他のチームに影響を与えることなく、1つのリポジトリでダンプ/フィルター/リロードをすばやく実行できます。
このルートを使用する場合のアドバイスの1つは、リポジトリごとに1つの巨大なファイルではなく異なる.confファイルを使用することです。これも、管理が簡単で、一部のタイムスタンプが古くなるという快適さを提供します。何か問題がある場合は、探すことができます。最近の変更が簡単になりました。
参照 リポジトリレイアウト svnbookから
リポジトリのコンテンツを整理するための標準的な推奨方法がいくつかあります。ほとんどの人は、開発の「メインライン」を保持するトランクディレクトリ、ブランチコピーを含むブランチディレクトリ、およびタグコピーを含むタグディレクトリを作成します。
/ trunk/ branches/ tags/
リポジトリに複数のプロジェクトが含まれている場合、管理者は通常、プロジェクトごとにレイアウトにインデックスを付けます。
このようなレイアウトの例を次に示します。
/ Paint/ trunk/ branches/ tags/ calc/ trunk/ branches/ tags/
もちろん、これらの一般的なレイアウトは無視してかまいません。あなたやあなたのチームに最適なものなら何でも、どんな種類のバリエーションも作成できます。何を選択しても、それは永続的なコミットメントではないことを忘れないでください。リポジトリはいつでも再編成できます。ブランチとタグは通常のディレクトリであるため、svnmoveコマンドはそれらを好きなように移動または名前変更できます。あるレイアウトから別のレイアウトに切り替えるには、一連のサーバー側の移動を発行するだけです。リポジトリでの整理方法が気に入らない場合は、ディレクトリを調整するだけです。
ただし、ディレクトリの移動は簡単ですが、他のユーザーにも配慮する必要があることを忘れないでください。あなたのジャグリングは、既存の作業コピーでユーザーを混乱させる可能性があります。ユーザーが特定のリポジトリディレクトリの作業コピーを持っていて、svn moveサブコマンドが最新のリビジョンからパスを削除した場合、ユーザーが次にsvn updateを実行すると、作業コピーはもう存在しないパスを表していると通知されます。その後、彼女は新しい場所にsvnスイッチすることを余儀なくされます。