【问题标题】:SVN combine projects + arrange by commit dateSVN 合并项目 + 按提交日期排列
【发布时间】:2015-02-26 15:15:19
【问题描述】:

因此,目前我们的项目位于它们自己的存储库中,但我们希望对其进行更改,以便项目位于一个存储库中。所以目前我们有:

  • 回购协议
    • 主干
    • 分支机构
  • 回购B
    • 主干
    • 分支机构
  • ...

我们正在努力:

  • 后备箱
    • repoA
    • repoB
    • ...
  • 分支机构
    • repoA
    • repoB
    • ...

我遇到的真正问题是我们希望新仓库中的提交按日期顺序排列。

我是否必须制作新的 repo 并将所有项目加载到其中,以便他们获得新的 rev 编号。然后以某种方式将提交移动到具有日期排序的第二个新仓库?

因此,我将不胜感激任何帮助我如何实现对组合 repo 的提交排序。

谢谢

【问题讨论】:

  • 可能,是的。这应该可以通过 svndump-ing 两个存储库来实现;然后,您必须修改每个转储中的路径,然后可能按提交顺序将它们压缩在一起,确保将任何元数据引用更新为您正在更改的提交编号,例如 svn:merge-info,然后将 svn 加载到新的存储库。 (它是带有“e”的“分支”。)

标签: svn repository svn-repository


【解决方案1】:

这里有两个问题。首先,要合并转储文件以使转速按日期顺序排列,您可以使用this tool(它对我有用)。但是,正如上面评论中所指出的,您可能会因为 rev 数字的变化而遇到问题(例如,我不知道该工具是否处理 svn:merginfo 属性)。

其次,重新排列路径名比较棘手。您需要更改转储文件中的路径名。我用this perl module 来做这种事情。

但更简单的答案是将转储文件加载到新的存储库中,如下所示:

svnadmin dump -q repoA | svnadmin load --parent-dir repoA mergedrepos
svnadmin dump -q repoB | svnadmin load --parent-dir repoB mergedrepos

是的,修订日期会出现问题,但我已经这样做了很多次,到目前为止还没有给我或我的用户带来任何问题。当您使用 repoA 或 repoB 中的 svn log 文件进行查询时,日期将按顺序排列,只有当文件在两者之间移动,或者您在整个存储库上运行 svn log 时,才会出现顺序问题。

加载两个存储库后,您可以将内容移动到所需的结构中,例如

svn mv file:///svn/mergedrepos/repoA/trunk file:///svn/mergedrepos/trunk/repoA

注意,您可能必须在加载和 mv 命令之前创建目录,但这留给读者作为练习。

【讨论】:

    【解决方案2】:

    (它是带有“e”的“分支”。)

    是的,我知道它是分支,在我们的 svn 中也是如此。 :)

    trent:感谢您提供的信息,我发现它会像您告诉我的那样工作。所以我写了一个脚本,将项目合并为一个。

    我知道只有在查看主干时,历史才会看起来很有趣,但好心的希望是提交将按日期排序。我还没有真正弄清楚如何按日期对提交进行排序。那么有人知道我如何将提交整理成日期顺序吗?

    编辑:看起来mergerepo script 会让我很容易地进行排序和合并

    【讨论】:

      【解决方案3】:

      我一直在为同样的问题苦苦挣扎。另一个答案中提到的SVN merge script 明确表示不鼓励合并大型独立存储库(这恰好是我的情况)。

      我找到的解决方案是将来自两个存储库的提交拆分并按日期对它们进行排序,然后将每个单独的提交分别加载到新存储库中。

      • 创建转储文件(它们具有.out 扩展名以避免与稍后使用的排序工具冲突)。

        svnadmin dump \path\to\repoA > repoA.out
        svnadmin dump \path\to\repoB > repoB.out
        
      • 将转储文件拆分为单独的修订版。为此,我使用了svndumptool(在上述合并脚本的网页中提到)。语法是svndumptool split src_file start_rev end_rev tgt_file。不幸的是,它一次提取一个范围的修订。为了克服这个问题,您可以使用以下批处理脚本:

        REM split.bat
        for /L %%I in (%2, 1, %3) do (
          svndumptool split %1 %%I %%I %4.%%I.dump
        )
        

        然后的语法是:

        split repoA.out 0 1000 repoA
        split repoB.out 0 2000 repoB
        

        它将生成一组.dump 文件。

      • 我已使用答案末尾列出的程序(我称之为svn_merge_by_date)按日期对修订进行排序并将它们相应地加载到新存储库中:svn_merge_by_date new_repo_name

      就我而言,存储库彼此完全独立,因此没有目录具有相同的名称。如果是您的情况,跟踪原始存储库并加载到不同的目录会更安全。每个转储文件都包含存储库的 UUID,因此您可以使用它们。

      这样,您既可以保留历史记录,也可以按时间对修订进行排序。


      svn_merge_by_date 的代码。它在 C++ 中,需要 Boost 来编译它。基本上它将扫描当前目录中的所有.dump 文件,按修订日期对它们进行排序并加载到新的存储库中(第一个命令行参数)。

      // DISCLAIMER: This code has been developed to solve a very specific
      //             and one-time problem and it is given AS IS.
      
      #include <iostream>
      #include <fstream>
      #include <boost/filesystem.hpp>
      
      namespace fs = boost::filesystem;
      
      void get_all(const fs::path& root, const std::string& ext, std::vector<fs::path>& ret)
      {
        if (!fs::exists(root) || !fs::is_directory(root)) return;
      
        fs::recursive_directory_iterator it(root), endit;
        while (it != endit) {
          if (fs::is_regular_file(*it) && it->path().extension() == ext) ret.push_back(it->path().filename());
          ++it;
        }
      }
      
      std::string get_date(const fs::path& filename)
      {
        std::ifstream f(filename.string());
        if (f) {
          std::string line;
          while (std::getline(f, line)) {
            if (line == "svn:date") { // date is two lines below
              std::getline(f, line);
              std::getline(f, line);
              return line;
            }
          }
        }
      
        return "";
      }
      
      int main(int argc, char* argv[])
      {
        if (argc < 2) return 0;
      
        const std::string svn_path(argv[1]);
      
        std::vector<fs::path> filenames;
        get_all(".", ".dump", filenames);
      
        std::vector<std::pair<std::string, fs::path>> sorted_files;
        for (auto it = filenames.begin(); it != filenames.end(); ++it) {
          const auto date = get_date(*it);
          if (!date.empty()) {
            sorted_files.push_back(std::make_pair(date, *it));
          }
        }
        std::sort(sorted_files.begin(), sorted_files.end());
      
        for (auto it = sorted_files.begin(); it != sorted_files.end(); ++it) {
          std::cout << it->first << " -> " << it->second << std::endl;
          const auto cmd = std::string("svnadmin load ") + svn_path + " < " + it->second.string();
          system(cmd.c_str());
        }
      
        return 0;
      }
      

      PS:如果您的存储库很大,比如说几 GB,我发现了一个很好的选择,可以将转储文件拆分为较小的文件(每个文件仅包含几百个修订版),然后再将它们拆分为单独的修订版。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-17
        • 1970-01-01
        • 2011-09-04
        • 1970-01-01
        • 2011-01-07
        • 2013-03-18
        • 2013-04-27
        • 1970-01-01
        相关资源
        最近更新 更多