2013-05-04 2 views
12

У нас есть два хранилища Subversion, каждый из которых имеет один проект. Итак:Объединить два отдельных хранилища SVN в один репозиторий Git

svn://server/svn/project_a 
svn://server/svn/project_b 

Они отдельных проекты, и в отдельных хранилищах с полностью раздельной фиксацией историей. Проект A имеет r1, r2, ... r100, а Project B имеет r1, r2, ... r400

Мы в конечном счете хотели бы объединить эти два хранилища SVN в один репозиторий Git. Независимо от того, что слияние может произойти в Git, или должно происходить в третьем временном хранилище SVN первым, мы в конечном счете хотим видеть:

git://server/svn/projects/ 

Что является хранилищем как с проектом A и B. Проект Они будут сохранены в отдельных папках, например:

git://server/svn/projects/project_a 
git://server/svn/projects/project_b 

Таким образом, конфликтов не будет «слияние» двух. Мы смогли безоговорочно использовать this answer, чтобы передать один проект SVN в единый проект Git с включенной историей фиксации.

Мы хотели бы, чтобы объединил наши два проекта SVN A и B в единый репозиторий Git, но мы хотим, чтобы коммиты были объединены по дате. т.е.:

8b8dad: Project A, r1 (first commit in Git) 
dbdffe: Project B, r1 (child of previous) 
0ae7f7: Project B, r2 ... 
615b51: Project A, r2 ... 
916e59: Project A, r3 ... 
85f241: Project B, r3 ... 

Возможно ли это? Должны ли мы объединить два репозитория SVN в один, а затем импортировать в Git? Или проще оставить их отдельно и выполнить слияние во время импорта Git?

+0

ли операции РЕПО SVN оба полностью линейна (т.е. нет ветвей)? –

ответ

3

Вот что мы в конечном итоге делает:

Шаг 1: Слияние SVN Хранилища в Temporary SVN Repository

Для этого требуется доступ к хранилищу SVN (не рабочие копии):

Во-первых, создавать файлы дампа каждого хранилища вы хотите объединить:

svnadmin dump project_a > dumps/a.dmp 
svnadmin dump project_b > dumps/b.dmp 
svnadmin dump project_c > dumps/c.dmp 

Затем, CRE съел новый репозиторий, который разместится слитые репозиториев:

svnadmin create svn-temp-project 

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

svn co file:///var/svn/svn-temp-project svn-temp-project-wc 
cd svn-temp-project-wc 
mkdir project_a 
mkdir project_b 
mkdir project_c 
svn add . --force 
svn ci -m "Added initial project directories." 

Затем вы можете загрузить каждый отдельный файл дампа в свой собственный специфический (!!) директория проекта:

svnadmin load svn-temp-project --parent-dir project_a < dumps/a.dmp 
svnadmin load svn-temp-project --parent-dir project_b < dumps/b.dmp 
svnadmin load svn-temp-project --parent-dir project_c < dumps/c.dmp 

Теперь у вас есть 3-объединенное хранилище SVN.

Шаг 2: Перенесите 3-объединенное хранилище SVN в хранилище Git

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

Сначала создайте файл authors.txt, который git-svn может использовать для определения автора каждой фиксации. Я использовал:

someguy = Some Guy <[email protected]> 
... 
(no author) = no_author <[email protected]_author> 

С этим авторы файл на месте, вы можете:

cd projects/ 
mkdir my-git-repository 
cd my-git-repository 
git svn init https://svn.mycompany.com/svn/svn-temp-project --no-metadata 
git config svn.authorsfile ../authors.txt 
git svn fetch 

Шаг 3: Очистка

Этот метод хорошо работает для объединения фиксации истории, но вы попадаете в SVN-подобные каталоги:

repo/project_a/trunk 
repo/project_a/branches 
repo/project_a/tags 
repo/project_b/trunk 
repo/project_b/branches 
repo/project_b/tags 
... 

Таким образом, перед нажатием вы должны перенести любые теги/ветки в Git. Мы этого не сделали. Наши теги не нужны, чтобы обойти, так как у нас были другие источники, чтобы их получить, и у нас не было филиалов для этих проектов.

После удаления каталогов branches и tags мы затем опустили содержимое trunk/ на один уровень, так что все было на уровне «root» проекта.

+0

Правильно ли это поддерживает историю фиксации для всех базовых репозиториев SVN? –

+0

@ JonathonReinhart Да, в нашем опыте, это так. –

3

Вот что я хотел бы сделать в оболочке Linux (непроверенных):

  1. конвертировать каждый в своей собственной мерзавца репо
  2. сделать третий GIT репозиторий с пустой первой фиксации

    git ci --allow-empty -m'Add empty, initial commit'

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

    git remote add repoA 'path/to/git/repoA'
    git remote add repoB 'path/to/git/repoB'

  4. принести репозиториях в пустой (это становится все объекты в один репозиторий)

    git fetch repoA
    git fetch repoB

  5. получить список коммитов в каждой репо с приставкой Временные метки Unix (секунды с 01.01.1970)

    git --no-pager log --format='%at %H' master >repoACommits
    git --no-pager log --format='%at %H' master >repoBCommits

  6. кошка их обоих в один, сортируется (по временной метки) списка, выбраковки метки времени:

    cat repoACommits repoBCommits | sort | cut -d' ' -f2 >orderedCommits

  7. в вашем новом репо, пробежать список, вишня собирание каждый (предположительно освоить)

    git co master
    cat orderedCommits | while read commit; do git cherry-pick $commit; done

Это все теоретическое, но я думаю, что это сработает. Я не знаю, что произойдет, если у вас есть конфликт слияния между ними. Я не уверен, что while остановится или продолжит попытки и не продолжит работу.

Я только что заметил, что вы упоминали о том, что каждый из них будет работать в отдельных папках в последней папке. Вам понадобится таинственный и мощный git filter-branch, чтобы сначала выполнить каждый репо отдельно, выполняя работу по перемещению добавленных вещей в папку, за совершение. Вероятно, это стоит новый вопрос, если на SO нет ответа.

+0

Гэри - спасибо за ваш ответ, он выглядит почти идеально, и мы попробуем его в ближайшее время. За ваше упоминание о том, как сохранить работу каждого репо в отдельных папках в последней папке, т.е. 'projects/projectA' и' projects/projectB', можно ли настроить удаленный Git на точку (в качестве адресата) на определенную подпапку? Так что 'fetch' не просто сбрасывает оба репозитория в корневой каталог? –

+0

Нет, это не сработает. Git хранит деревья, которые являются рекурсивными каталогами (1 текстовый файл для каждого каталога). В этой процедуре нет простого способа указать их где-то еще. Вам нужно отфильтровать каждую отдельную репо, чтобы создать папку и переместить все в нее, прежде чем вы сможете двигаться дальше. Я просто тестировал это локально, и он работал: 'git filter-branch -tree-filter 'mkdir -p newfolder; find -mindepth 1 -maxdepth 1 -not -name newfolder -exec mv {} $ fname newfolder \; ' master' - изменить 3 экземпляра «новой папки» на любое имя, которое вы хотите для подкаталога конкретной конкретной репо. –

+0

После того, как вы это сделали, вы можете проверить, выполнив «git whatchanged --oneline» - все файлы, перечисленные для каждой фиксации, должны иметь имя папки, предшествующее им. * Затем * вы можете получить журналы, cat/sort them и использовать их для вишневого выбора. Заметка о наборе вишни - возможно, у вас будут какие-то пустые коммиты, что приведет к сбою команды вишневого захвата, о которой я изначально упоминал. Добавьте '--allow-empty', чтобы пройти это после' cherry-pick'. –

5

Итак, я попробовал метод Крейга, но в конце концов это оставило меня с несколько неудовлетворительной историей в объединенном хранилище. Я обнаружил, что проверка всех репозиториев SVN на отдельные git, а затем их разветвление сделало приятную историю, где встречаются три ветки.

Итак, сначала сделайте шаг «авторы», чтобы создать авторов.ТХТ:

someguy = Some Guy <[email protected]> 
... 
(no author) = no_author <[email protected]_author> 

Теперь вы должны проверить все Svn операции РЕПО с использованием мерзавца:

mkdir proja projb projc ... 

Теперь вы должны повторить следующее для каждого проекта, а так как ваши сделки РЕПО, вероятно, не одна папка делать дополнительные фиксации:

cd proja 
git svn init https://svn.mycompany.com/svn/proja --no-metadata 
git config svn.authorsfile ../authors.txt 
git svn fetch 

#here comes the additional part: 
mkdir -p proja     #proja/proja 
git mv -k * proja    #move everything in there 
git commit -m "subtree proja" 

Тогда я пошел и сделал свой новый комбинированный репо, в котором я использовал другую ветвь для каждого подпроекта:

mkdir ../superproj 
cd ../supeproj 
git init 
git commit --allow-empty  #so that we have a master branch 
git branch proja projb projc... 

следующие потребности быть повторен для каждого подпроекта:

git checkout proja 
git remote add proja_rm ../proja 
git pull proja_rm    #probably add a branch (e.g. master) 
git remote rm proja_rm   #cleanup 

Наконец, вы можете объединить все это в ваш мастер

git checkout master 
git merge proja projb projc... #it all comes together 
git push whereeveryouwant 
+0

Обратите внимание, что в git 2.9 вы должны добавить '--allow-unrelated-history' при слиянии, где« #it all together » –

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