Перенос SVN-репозитария в git

22 июля 2009, обновлена 29 мая 2011

Твое сердце уже с git, а старые репозитарии остались под SVN. Что же делать? Простое решение — закоммитить текущее состояние проекта в гит — нас явно не устраивает, хочется ведь и историю сохранить, и ветки перетянуть. Приступим.

Фанбои заявляют, что переход с SVN на git проходит безболезненно. Ну и пусть себе заявляют, мы-то знаем, что все зависит от сложности репозитария, того, какие возможности SVN использовались, и, также, наличия пустых папок. Мне нужно было переносить ветки и svn:ignore. (И пустые папки, конечно.)

Устанавливаем git-svn

Это, собственно, часть гита, так что достать ее можно без проблем. Например, на Ubuntu это делается так:

sudo apt-get install git-svn

Собираем авторов коммитов

Дело в том, что в SVN пользователи – это просто идентификаторы, а в git – email-ы (Еще один плюс гита налицо.)

Выполняем такой вот скрипт в папке SVN-репозитария:

#!/usr/bin/env bash
authors=$(svn log -q | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
for author in ${authors}; do
  echo "${author} = NAME <EMAIL>";
done

Результат работы скрипта сохраняем куда-нибудь в ~/svn-authors, не забывая заполнить реальные адреса.

Клонируем репозитарий

Указываем URL репозитария, а НЕ транка!

git svn clone -s --authors-file=/home/user/svn-authors svn://repo/location .
  • -s — понимать стандартные папки SVN (trunk, branches, tags)
  • --authors-file=... — использовать файл с авторами с предыдущего шага

Теперь имеем git-репозитарий с содержимым SVN – но пока еще не полный. (Без пустых папок, ну ты понял.)

Разбираемся с ветками

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

git fetch . refs/remotes/*:refs/heads/*

Что с пустыми папками?

А, это. Ну в общем git хранит только информацию о файлах. О папках он вообще ничего не знает. Поэтому папку без файлов закоммитить не удастся, и, соответственно, при переносе из SVN они все теряются. Придется создавать их ручками. Чтобы закоммитить такую папку, нужно создать в ней какой-нибудь файл — традиционно это пустой .gitignore.

Кстати, git-svn сообщает о несозданных папках в лог, который находится в .git/svn/branch/unhandled.log.

Вытягиваем svn:ignore

Для каждой ветки:

git checkout branch
git svn create-ignore
git commit -a -m "imported svn:ignore"

Само собой, при попытке создать .gitignore для несуществующей (а ранее пустой) папки скрипт выкинет ошибку. Пусть это будет для тебя знаком, что такую папку надо создать.

Вычищаем из репозитария упоминания об SVN

Наконец, мы готовы отдать проект в руки git. Разумеется, репозитарий SVN как был, так и остался, поскольку работаем мы с локальной копией. Но в дальнейшем планируется использовать только git, можно убрать из репозитария данные git-svn.

Удаляем все svn-ветки – те, которые git считает удаленными (remote). Кроме того, удаляем ту ветку, которая является мастером; практика показывает, что это самая свежая ветка. Еще можно удалить мастер, а потом переименовать самую свежую ветку в мастер.

for branch in `git branch -r`; do git branch -rd $branch; done
git branch -d trunk

Последний штрих: удаляем метаданные git-svn

git config --remove-section svn-remote.svn
rm -Rf .git/svn/

Готово! Имеем полностью перенесенный под git репозитарий. Можно пользоваться им сразу, а можно залить на github или на свой сервер в gitosis.



Тридцать комментариев. Напиши еще один
  1. 1a74541e905579cc2f21a29515c6d875 # 22 июля 2009 dmishe написал:

    >>а можно залить на github
    github сам все импортирует с историей вместе.

  2. B0f63bbe7e2f1a89feedbde170e8e896 # 23 июля 2009 Nikolai написал:

    А что делать, если фирма не хочет (пока) переходить на гит, но локально уже гит на реальном проекте попробовать хочется? Какие-то подобные статьи имеются?

  3. F93d6b7e707b83cb2ff8257f558463ae # 24 июля 2009 Max написал:

    Если в svn использовались svn:externals, то все так просто не пройдет, ибо это не поддерживается git-svn и собственно самим git тоже.

  4. 4fc6c33f1a1d114204a66ef7bdeaf1e2 # 24 июля 2009 Miroslav Rubanets написал:

    мое приключение с гит имело целью использовать его для работы с центральным репозиторием.
    Первый облом – время сетевого импорта.
    Второй облом – он не осилил импорт из локального репо полученного svnsync'ом (svn 1.6, гит июльский ). 3й облом – черепаший ui отказывался выполнять команды с центральным репозиторием (версия была свежая). Из командной строки fetch шел, но указать ему ключик от cygwin ssh мне не удалось (это к слову про еще один кривой юникс под виндой).
    так что пока не впечатлило.
    зы идея выкладывания корпоративного репо на гитхаб жжот напалмом.

    1. 777894ea5153122bfa6b83f5bbf23622 # 24 июля 2009 Леонид Шевцов (автор) написал:

      Сетевой импорт вытягивает содержимое всех ревизий из SVN, разумеется, он занимает долгое время. Я бы советовал вытягивать его прямо на сервере, так git-svn не придется таскать по сети столько данных.

      Черепаший ui – это tortoisegit? Да, он еще очень сырой.

      Не знаю, как с гитом под windows, говорят, что плохо, но с другой стороны рядом со мной сидит человек, он замечательно работает c msysgit с авторизацией по ключу.

  5. 02c7cf8a5e35a290c1d436602adedfc9 # 19 сентября 2009 Алексей (createit.ru) написал:

    Спасибо, помогло. Самому было трудно разобраться…

  6. 82896ae7662ba5391678578911d5a9b4 # 01 октября 2009 mikhailov (railsgeek.com) написал:

    а что делать, если заказчик ну никак не хочет слышать про гит – вообще падает в обморок от этого слова :)
    делать так:
    $ git init
    $ echo .svn > .gitignore # Git будет игнорить папки SVN
    $ git add .
    $ git commit -m «git init»
    $ svn propset svn:ignore .git # property ‘svn:ignore’ set on ‘.’
    $ svn commit -m «ignoring git folder»
    $ git add .
    $ git commit -m «commit for deploy to heroku»

    И работать с гитом локально, а заказчик будет видеть прежний svn-репозиторий

  7. 22203482572193fd53863a81ca947635 # 05 октября 2009 Сергей Морозов написал:

    Скажите, правильно ли я понимаю, что для того, чтобы иметь основной, «центральный», репозиторий где-то на удаленном хосте, доступном через SSH, нужно, чтобы на этом хосте был установлен Git?

    Для меня эта необходимость до сих пор неочевидна. Почему для того, чтобы удаленно пользоваться файлами (по сути ведь репозиторий — это файлы), нужно дополнительное серверное ПО?

    Можно ли как-то вынести центральный репозиторий на shared-хостинг, на котором нет возможности устанавливать дополнительное ПО?

    1. 777894ea5153122bfa6b83f5bbf23622 # 05 октября 2009 Леонид Шевцов (автор) написал:

      Если кратко – Git не умеет работать с удаленным репозитарием как с файлами. Это даже описано в Git FAQ

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

  8. 82896ae7662ba5391678578911d5a9b4 # 10 ноября 2009 mikhailov (railsgeek.com) написал:

    git-svn вполне работоспособная альтернатива тупому svn

  9. 59a5a071e6c747248bcc003b92195566 # 03 марта 2011 Oleg Lobach (lobach.info) написал:

    команду надо поправить:

    вместо git svn clone -s -clone-authors-file=/home/user/svn-authors svn://repo/location .
    надо git svn clone -s --authors-file=/home/user/svn-authors svn://repo/location .

    1. 777894ea5153122bfa6b83f5bbf23622 # 03 марта 2011 Леонид Шевцов (автор) написал:

      Спасибо! Опечатался.

    2. 4aa6091cee29e574f7fff705ddd3fa7f # 19 сентября 2011 Bogdan (yurov.me) написал:

      Зачем там вообще -s? Я пока ключ не увидел, не мог разобраться. Чтобы новичка сообщениями об ошибках не пугать?

      1. 59a5a071e6c747248bcc003b92195566 # 19 сентября 2011 Oleg Lobach (lobach.info) написал:

        Этот ключ указывает на то, что структура репозитария каноническая, что позволяет не указывать явно пути к транку, бранчам и тэгам

  10. Ee6914bab207793e1eb805b2d755abc7 # 31 марта 2011 Руслан написал:

    Файл с авторами должен быть в формате:

    автор = автор <мыло>

    По крайней мере у меня только так работает, а если просто автор = мыло – отваливается

    1. 777894ea5153122bfa6b83f5bbf23622 # 31 марта 2011 Леонид Шевцов (автор) написал:

      Похоже, что да. Спасибо.

  11. 35c11634f832bb535a7c84f1cf575ee7 # 06 апреля 2011 Anton Fedorov (blog.datacompboy.ru) написал:

    К слову сказать, git-svn последних версий сам создаёт пустые папки в конце экспорта.

  12. 1032204_100x100_normal # 10 апреля 2011 Павел Аргентов (@argent_smith) написал:

    После выполнения «git svn clone -s —authors-file=/home/user/svn-authors svn://repo/location» имею пустую репу. Это так и надо? Или все надо делать на svn-сервере локально?

    1. 777894ea5153122bfa6b83f5bbf23622 # 10 апреля 2011 Леонид Шевцов (автор) написал:

      Нет, это что-то не так пошло. SVN-сервер может быть где угодно, лишь бы он доступен был.

      …А /home/user/svn-authors и svn://repo/location на настоящие значения заменили?

      1. F7e47926681db4c996fe0988f306c770 # 12 августа 2011 Виктор написал:

        Заменил конечно же. Все равно создает пустой репозиторий… что делать?

        1. F7e47926681db4c996fe0988f306c770 # 12 августа 2011 Виктор написал:

          Ага, нашел. Вот что сделал:

          mkdir test
          cd test
          svn co svn://repo/location
          git svn clone svn://repo/location

          и все!

  13. Default_profile_4_normal # 29 мая 2011 Вадег (@bad_tjay) написал:

    Небольшие поправки для git version 1.7.1
    Формат файла svn-authors должен быть:

    svn.username = User Name <email>

    Например:
    vasya.pupkin = Vasiliy Pupkin <vasya.pupkin@acme.com>

  14. 86a3ed9041a500c5a0a9887be7fa2dcd # 02 июня 2011 sn00p написал:

    Спасибо огромное, сделали по статье, все работает

  15. 1360900f8549e64b0f55377a87502a0e # 12 декабря 2011 dipwoodle написал:

    Импортируется история только из ~100 последних коммитов. Как достать всю?

    1. 1360900f8549e64b0f55377a87502a0e # 12 декабря 2011 dipwoodle написал:

      убрал флаг -s и все заработало

      1. 777894ea5153122bfa6b83f5bbf23622 # 12 декабря 2011 Леонид Шевцов (автор) написал:

        Это при стандартной раскладке каталогов (trunk, branches, tags)?

        1. 1360900f8549e64b0f55377a87502a0e # 12 декабря 2011 dipwoodle написал:

          Вот все мои задокументированные действия:

          Bash-скрипт сохранил в svnAuthors.sh.
          mkdir ~/svnwork/
          cd svnwork/
          svn co file:///data/svn/rep .
          mv /path/to/svnAuthors.sh ~/svnwork/.
          chmod u+x svnAuthors.sh
          ./svnAuthors.sh >> ~/svn_authors
          vim ~/svn_authors // отредактировал
          mkdir ~/gitwork/
          cd ~/gitwork/
          git svn clone -s —authors-file=~/svn_authors file:///data/svn/rep .

          Всего у меня 1778 коммитов. Это клонирование сделало, начиная с 1671. Бранчи создало, все круто. Если я делаю без -s, то бранчи не создает, но коммиты с самого начала.

        2. 1360900f8549e64b0f55377a87502a0e # 12 декабря 2011 dipwoodle написал:

          да, пути к каталогам:

          /data/svn/rep/branches/
          /data/svn/rep/tags/
          /data/svn/rep/trunk/

      2. 1360900f8549e64b0f55377a87502a0e # 12 декабря 2011 dipwoodle написал:

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

  16. D60ecf2232fe1449d226fa26415cd932 # 12 января 2012 SerGO написал:

    импорт с Svn –> Git прошел успешно, затем в svn сделали изменения, как правильно подтянуть эти изменения в git? git svn rebase? Или просто fetch а потом слить?

(нужна разметка?)

  • **жирный**
  • > цитата

отменить