2015-02-26 3 views
2

Так что в настоящее время наши проекты находятся в собственном репозитории, но мы хотим изменить его, чтобы проекты находились под одним репо. Так в настоящее время мы имеем:SVN объединяет проекты + упорядочивается по дате фиксации

  • repoA
    • ствол
    • Филиалы
  • repoB
    • ствол
    • Филиалы
  • . ..

и мы собираемся для:

  • стволу
    • repoA
    • repoB
    • ...
    • Филиалы
    • повторно Poa
    • repoB
    • ...

Реальная проблема у меня в том, что мы хотели бы иметь коммиты в новом репо, чтобы быть в хронологическом порядке.

Должен ли я сделать новое репо и загрузить все проекты в это, чтобы они просто получили новые номера оборотов. Затем каким-то образом переместите фиксации на второе новое репо с упорядочением даты?

Так что любая помощь, как я могу добиться упорядочения коммитов в комбинированное репо, будет оценена по достоинству.

Thanks

+0

Возможно, да. Это должно быть возможным благодаря svndump-ing обоих хранилищам; вам придется изменить пути в каждом дампе, а затем, возможно, закрепить их вместе в порядке фиксации, убедившись, что вы обновите любые ссылки на метаданные, чтобы фиксировать числа, которые вы меняете, такие как svn: merge-info, затем svn load в новый репозиторий. (И это «ветви» с «е».) – Rup

ответ

2

Здесь есть две проблемы. Во-первых, чтобы объединить файлы дампа, чтобы обороты были в порядке даты, вы можете использовать this tool (это сработало для меня). Однако, как отмечено в комментарии выше, вы можете столкнуться с проблемами из-за изменения номеров оборотов (например, я не знаю, имеет ли этот инструмент свойства 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 

Да, даты пересмотра будет в порядке, но я сделал это несколько раз и это не вызвало у меня или моих пользователей никаких проблем до сих пор. Когда вы выполняете запросы, используя svn-журнал файлов в repoA или repoB, даты будут в порядке, только если файлы будут перемещаться между ними или если вы запустите svn-журнал во всем репозитории, появится проблема с порядком.

После того, как вы загрузили два репозитория, вы можете перемещать объекты в нужную вам структуру, например.

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

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

1

(И это «ветвь» с «е».)

Да, я знаю, что это ветвь и то, как это в нашем СВН, а также. :)

trent: спасибо за информацию, я выяснил, что это сработает, как вы сказали мне. Поэтому я написал сценарий, который объединяет проекты в один.

Я знаю, что история будет выглядеть смешно только при взгляде на багажник, но доброе пожелание состояло в том, что коммиты будут сортироваться по дате. Я действительно не понял, как я могу сортировать фиксации по дате. Так у кого-нибудь есть идея, как я мог бы разобрать, чтобы фиксации были в порядке даты?

редактировать: Посмотрите, как mergerepo script позволит мне сделать сортировку и слияние довольно легко

0

Я боролся с той же проблемой в течение времени. 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: если хранилище велико, скажем, несколько гигабайтов, я нашел хорошую возможность разделить дамп-файлы в файлы меньшего размера (содержащие только несколько сотен изменений каждый), прежде чем продолжить разделить их на отдельные изменения.

Смежные вопросы