Перенос существующего Git-репозитория в SVN

385

Я делал всю свою работу в Git и подталкивал к GitHub. Я был очень доволен как программным обеспечением, так и сайтом, и у меня нет желания менять свою рабочую практику на этом этапе.

Мой доктор PhD советует всем студентам хранить свою работу в хранилище SVN, которое находится в университете. Я нашел тонны документации и учебных пособий о том, как перенести существующий репозиторий SVN в Git, но ничего о переносе репозитория Git в новый репозиторий SVN. Я ожидаю, что должен быть какой-то способ сделать это с помощью сочетания git-svn и свежей ветки, перебазирования и всех этих замечательных терминов, но я новичок в Git и не чувствую уверенности ни в одном из них.

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

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

cflewis
источник
1
Примечание: вы, вероятно, потеряете свои оригинальные штампы с датой, когда вы сделаете это. Новые даты будут основаны на времени импорта в Subversion.
Нобар
Для тех , кто ищет более актуальную информацию некоторые из них могут найти следующее сообщение полезные во время поиска по автоматизации: deliciousbrains.com/deploying-wordpress-plugins-travis
Джош Habdas

Ответы:

403

Мне это тоже нужно было, и с помощью ответа Бомбе + немного повозиться, я заработал. Вот рецепт:

Импорт Git -> Subversion

1. cd /path/to/git/localrepo
2. svn mkdir --parents protocol:///path/to/repo/PROJECT/trunk -m "Importing git repo"
3. git svn init protocol:///path/to/repo/PROJECT -s
4. git svn fetch
5. git rebase origin/trunk
5.1.  git status
5.2.  git add (conflicted-files)
5.3.  git rebase --continue
5.4.  (repeat 5.1.)
6. git svn dcommit

После # 3 вы получите загадочное сообщение, подобное этому:

Используя более высокий уровень URL: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

Просто игнорируй это.

Когда вы запустите # 5, вы можете получить конфликты. Решите их, добавив файлы с состоянием «unmerged» и возобновив их перебазирование. В конце концов, вы закончите; затем выполните синхронизацию с репозиторием SVN, используя dcommit. Это все.

Синхронизация репозиториев

Теперь вы можете синхронизироваться из SVN в Git, используя следующие команды:

git svn fetch
git rebase trunk

И для синхронизации из Git в SVN используйте:

git svn dcommit

Конечная нота

Возможно, вы захотите попробовать это на локальной копии, прежде чем применять к живому репозиторию. Вы можете сделать копию своего репозитория Git во временное место; просто используйте cp -r, так как все данные находятся в самом хранилище. Затем вы можете настроить файловый репозиторий тестирования, используя:

svnadmin create /home/name/tmp/test-repo

И проверьте рабочую копию, используя:

svn co file:///home/name/tmp/test-repo svn-working-copy

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

Приложение: Если вы испортили git svn init

Если вы случайно запустили git svn initнеправильный URL-адрес и не были достаточно умны, чтобы сделать резервную копию своей работы (не спрашивайте ...), вы не можете просто выполнить эту же команду еще раз. Однако вы можете отменить изменения, выполнив:

rm -rf .git/svn
edit .git/config

И удалить раздел [svn-remote "svn"]раздела.

Вы можете запустить git svn initзаново.

troelskn
источник
2
Хороший ответ. Это также портит даты фиксации?
Дрю Ноакс
4
Хорошие вопросы - к сожалению, я тоже не знаю ответа. Это более практическое руководство по тому, что я нашел для работы. Я не до конца понимаю все детали. Что касается дат фиксации, я думаю, вы могли бы сделать тест и выяснить это. Помните, что вы можете инициировать локальное (основанное на fs) svn-репо для тестирования.
troelskn
10
Я следовал этим же шагам, используя «git rebase --onto trunk --root» вместо шага 5, и добился гораздо большего успеха. Только горстка конфликтов слияния для разрешения, а не тонны.
Куби
5
В моем случае эта последовательность не сработала. Всегда отображалось сообщение «Невозможно определить восходящую информацию SVN из истории HEAD». Таким образом, dcommit невозможно.
Федир Рыхтик
2
Неважно, я пытался стать умным и опустить -s, так как я не хотел следовать стандартной настройке SVN (trunk / branch / tags /). Не мог заставить это работать вообще без этого.
Джеймс МакМэхон
33

Вот как мы это сделали:

Клонируйте свой репозиторий Git где-нибудь на своей машине.

Откройте .git / config и добавьте следующее (из раздела «Поддержка зеркала SVN только для чтения» в репозитории Git ):

[svn-remote "svn"]
    url = https://your.svn.repo
    fetch = :refs/remotes/git-svn

Теперь из окна консоли введите:

git svn fetch svn
git checkout -b svn git-svn
git merge master

Теперь, если по какой-то причине это не работает, введите эти три строки:

git checkout --theirs .
git add .
git commit -m "some message"

И, наконец, вы можете передать в SVN:

git svn dcommit

Примечание. После этого я всегда удаляю эту папку.

Алекс Руайяр
источник
6
+1 это на самом деле сработало для меня (у меня нет ствола / основания), в отличие от других ответов, которые продолжали даватьUnable to determine upstream SVN information from HEAD history.
stijn
2
Еще одно приятное резюме: codeography.com/2010/03/17/howto-mirror-git-to-subversion.html
Томми,
2
Я попробовал эту технику, но она не импортировала историю. Кстати, «мастер git merge» теперь является «git merge - мелкий-несвязанный мастер историй»
Беренд де Бур
1
Если вы абсолютно хотите переписать то, что в SVN, на то, что в git, используйте git merge -s recursive -Xtheirs --allow-unrelated-histories master.
user1475814
28

Использование git rebaseнапрямую приведет к потере первого коммита. Git относится к этому по-другому и не может перебазировать это.

Существует процедура, которая сохранит полную историю: http://kerneltrap.org/mailarchive/git/2008/10/26/3815034

Я напишу решение здесь, но кредиты для Бьёрна.

Инициализировать git-svn:

git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2

--Prefix дает вам удаленные ветви отслеживания, такие как «svn / trunk», что хорошо, потому что вы не получите двусмысленных имен, если вы будете называть вашу локальную ветку просто «trunk». И -sэто ярлык для стандартного макета ствола / теги / ветви.

Получить исходный материал из SVN:

git svn fetch

Теперь посмотрите хэш вашего корневого коммита (должен отображаться один коммит):

git rev-list --parents master | grep '^.\{40\}$'

Затем получите хэш пустого коммита транка:

git rev-parse svn/trunk

Создайте прививку:

echo <root-commit-hash> <svn-trunk-commit-hash> >> .git/info/grafts

Теперь «gitk» должен отображаться svn/trunkкак первый коммит, на котором основана ваша основная ветка.

Сделайте прививку постоянной:

git filter-branch -- ^svn/trunk --all

Бросьте трансплантат:

rm .git/info/grafts

Гитк все равно должен показываться svn/trunkв родословной мастера.

Линеаризуйте свою историю поверх ствола:

git svn rebase

А теперь "git svn dcommit -n" должен сообщить вам, что он собирается фиксировать транк.

git svn dcommit
Питер Мортенсен
источник
Можете ли вы объяснить, как эта техника отличается от выше, более четко.
cmcginty
3
Когда я пытаюсь "git rev-parse svn / trunk", он сообщает о неизвестной ревизии или пути не в рабочем дереве.
Адам Несс
Это единственный ответ, который работал для меня, за исключением того, что шаги git filter-branch и drop graft были не нужны: я сделал ребаз после создания трансплантата, а затем сделал git svn dcommit.
fc7
8

Создайте новый каталог в хранилище Subversion для своего проекта.

# svn mkdir --parents svn://ip/path/project/trunk

Перейдите к проекту, управляемому Git, и инициализируйте git-svn.

# git svn init svn://ip/path/project -s
# git svn fetch

Это создаст один коммит, потому что ваш каталог проекта SVN по-прежнему пуст. Теперь перебазируйте все на этом коммите, git svn dcommitи все готово. Это серьезно испортит ваши даты коммитов.

Бомбы
источник
Я использовал этот ответ с инструкциями на hassox.blogspot.com/2007/12/using-git-with-svn.html Я следовал этим командам, затем "#git branch -a", чтобы увидеть имя соединительной линии. Затем: # git checkout -b local-svn trunk # git merge master # git svn dcommit Не забудьте .gitignore каталог .svn!
cflewis
Поскольку я только что проделал ту же самую операцию, я хотел сделать явное, что в течение некоторого времени (январь '09) git может выполнить операцию rebase для корневого коммита. Это делает процесс намного проще, чем указывают многие старые статьи, см. Комментарии на its.arubything.com/2009/1/4/…
Луи Жакомет
Что делает опция "-s" git svn init? Я не вижу этого на страницах руководства для git svn.
Натан
Прочитайте man-страницу снова, возможно, ищите «-s», потому что она там. Это псевдоним для «--stdlayout».
Бомба
7

Git -> SVN с полной историей коммитов

У меня был проект Git и мне пришлось перенести его в SVN. Вот как я это сделал, сохранив всю историю коммитов. Единственное, что теряется - это оригинальное время коммита, так как libSVN установит местное время, когда мы это сделаем git svn dcommit.

Как:

  1. Есть SVN-репозиторий, куда мы хотим импортировать наш материал и клонировать его с помощью git-svn:

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. Иди туда:

    cd repo.git-svn
    
  3. Добавьте удаленный репозиторий Git (в этом примере я использую C: /Projects/repo.git ). Вы хотите нажать на SVN и дать ему имя old-git:

    git remote add old-git file:///C/Projects/repo.git/
    
  4. Извлеките информацию из основной ветки из старого Git-репозитория в текущий репозиторий:

    git fetch old-git master
    
  5. Извлеките основную ветку удаленного old-git в новую ветвь с именем old в текущем хранилище:

    git checkout -b old old-git/master`
    
  6. Перебазируйте, чтобы положить ГОЛОВУ поверх старого git / master. Это сохранит все ваши коммиты. В основном это сводится к тому, чтобы взять всю вашу работу, выполненную в Git, и поставить ее поверх работы, к которой вы обращаетесь из SVN.

    git rebase master
    
  7. Теперь вернитесь к вашей основной ветке:

    git checkout master
    

    И вы можете видеть, что у вас есть чистая история коммитов. Это то, что вы хотите подтолкнуть к SVN.

  8. Разместите свою работу в SVN:

    git svn dcommit
    

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

codingdave
источник
Аналогичный процесс также подробно описан на chani.wordpress.com/2012/01/25/…
TWiStErRob
Похоже. Тем не менее, я нахожу ее путь довольно запутанным, а мой намного короче (8 шагов, чем 19/23). Возможно, я не понимаю ее правильно, но я думаю, что она смешивает команды SVN и GIT в своей второй пули.
codingdave
Ах, да, разница в том, что ваш процесс импортирует git в корень git svnрепозитория SVN, а ее импортирует в подпапку, поэтому необходимо несколько предварительных операций.
TWiStErRob
На шаге 7, не должно ли быть git merge old? Для меня кажется, что вы делаете мастером dcommit, что вы не изменились ?!
Александр
@ Александр, используя 'git rebase master', приводит к ускоренному слиянию, то есть к линейному слиянию без коммита слияния с двумя родителями. Мы хотим иметь линейную историю здесь.
codingdave
4

Я бы предложил очень короткую инструкцию по 4 командам с использованием SubGit . Смотрите этот пост для деталей.

Дмитрий Павленко
источник
3

Мне нужно было зафиксировать свой существующий Git-репозиторий в пустом SVN-репозитории.

Вот как мне удалось сделать это:

$ git checkout master
$ git branch svn
$ git svn init -s --prefix=svn/ --username <user> https://path.to.repo.com/svn/project/
$ git checkout svn
$ git svn fetch
$ git reset --hard remotes/svn/trunk
$ git merge master
$ git svn dcommit

Работало без проблем. Я надеюсь, что это помогает кому-то.

Поскольку мне пришлось авторизоваться под другим именем пользователя в SVN-хранилище (я originиспользую аутентификацию с использованием открытого / открытого ключа), мне пришлось использовать это --usernameсвойство.

Джей Лински
источник
Вам может потребоваться установить, git-svnпрежде чем это станет возможным, см. stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive
2

Если вы хотите продолжать работать с Git в качестве основного репозитория и вам просто нужно время от времени «экспортировать» ревизии в SVN, вы можете использовать Tailor для синхронизации SVN-репозитория. Он может копировать ревизии между различными системами контроля версий и обновлять SVN с изменениями, которые вы делаете в Git.

Я не пробовал преобразование Git в SVN, но для примера SVN -> SVN посмотрите этот ответ .

STH
источник
2

Еще одна последовательность, которая работала (с некоторыми комментариями на каждом шаге):

  1. Установить git-svnи subversionинструментарий:

    sudo apt-get install git-svn subversion
    
  2. Переключить внутри PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. Создайте путь к проекту на сервере Subversion (к сожалению, текущий git-svnплагин имеет дефект по сравнению с TortoiseSVN). Невозможно сохранить исходный код непосредственно в PROJECT_FOLDER. Вместо этого по умолчанию он загрузит весь код в PROJECT_FOLDER/trunk.

    svn mkdir - родительский протокол: /// путь / к / repo / PROJECT_FOLDER / trunk -m "создание заполнителя git repo"

Это место, где trunkв конце пути обязательно

  1. Инициализировать git-svnконтекст плагина внутри .gitпапки

    git svn init -s protocol:///path/to/repo/PROJECT_FOLDER
    

    Это место, где trunkв конце пути нет необходимости

  2. Получить информацию о пустом Subversionхранилище

    git svn fetch
    

    Этот шаг помогает синхронизировать сервер Subversion с git-svnплагином. Это момент, когда git-svnплагин устанавливает remotes/originпуть и связывает его с trunkподпапкой на стороне сервера.

  3. Перебазирование старых коммитов Git произошло до того, как git-svnплагин включился в процесс (этот шаг не является обязательным )

    git rebase origin/trunk
    
  4. Добавьте новые / измененные файлы для фиксации (этот шаг является обычным для действий Git и является необязательным )

    git add .
    
  5. Зафиксируйте только что добавленные файлы в локальный репозиторий Git (этот шаг не является обязательным и применим только в том случае, если был использован шаг 7):

    git commit -m "Importing Git repository"
    
  6. Передача всей истории изменений проекта на сервер Subversion:

    git svn dcommit
    
Олег Кокорин
источник
1

Вы можете сделать новый SVN-репозиторий. Экспортируйте свой проект Git (выделив файлы .git). Добавьте его в репозиторий SVN (инициализируя репозиторий тем, что у вас было в Git). Затем используйте инструкции по импорту SVN-репозиториев в свежий проект Git.

Но это потеряет вашу предыдущую историю Git.

Васил
источник
1

Если вам не нужно использовать какой-либо конкретный SVN, и вы используете GitHub, вы можете использовать их разъем SVN.

Более подробная информация здесь: Сотрудничество на GitHub с Subversion

elmariofredo
источник
SVN что? В ( «... любой конкретный SVN и ...» ). Версия SVN? Клиент SVN? Или что-то другое?
Питер Мортенсен
1

Я хотел бы поделиться отличным инструментом, используемым в сообществе WordPress, под названием Scatter

Git WordPress плагины и немного рассудка

Это позволяет пользователям автоматически отправлять свои репозитории Git на wordpress.org SVN. Теоретически этот код может быть применен к любому репозиторию SVN.

R109
источник
Ссылка, похоже, эффективно битая ( «Сервер evansolomon.me слишком долго не отвечает» ).
Питер Мортенсен
1

Недавно мне пришлось перенести несколько репозиториев Git в SVN, и после того, как я попробовал все решения, которые смог найти, для меня наконец-то работал Mercurial (да, с использованием третьей VCS). Используя это руководство , я придумал следующий процесс (в Linux, но основная идея должна работать и в Windows).

  1. Необходимые пакеты:

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. Mercurial необходимо настроить, добавив следующее в ~/.hgrc:

    [extensions]
    hgext.convert=
    
  3. Создайте несколько временных рабочих каталогов (у меня было несколько репозиториев для миграции, поэтому я создал каталоги для версий SVN и Git, чтобы разделить их):

    $ mkdir svn
    $ mkdir git
    
  4. Создайте пустой локальный репозиторий SVN:

    $ svnadmin create svn/project
    
  5. Клонировать существующий репозиторий Git:

    $ git clone server/path/project.git git/project
    
  6. Пусть Mercurial сделает свое дело:

    $ hg convert --dest-type svn git/project svn/project
    
  7. Теперь SVN-репозиторий должен содержать полную историю коммитов, но не с оригинальными временными метками. Если это не проблема, пропустите следующую часть до шага 11.

  8. С небольшой работой, можно изменить дату и время каждого коммита . Поскольку мои репозитории довольно малы, для меня было возможно сделать это вручную. Сначала создайте pre-revprop-changeловушку в репозитории SVN со следующим содержимым, чтобы можно было изменить необходимое свойство:

    #!/bin/bash
    exit 0;
    

    Этот скрипт должен быть выполнен исполняемым:

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial создал рабочую копию репозитория SVN с именем project -wc, поэтому переключитесь на нее и измените время фиксации:

    $ cd project-wc
    $ svn propedit svn:date --revprop -r 1
    

    Введите правильную дату и время (обратите внимание на часовые пояса!) И сохраните. Вы должны получить сообщение «Установите новое значение для свойства svn: date в ревизии 1».
    Теперь промойте и повторите для каждой другой ревизии.

  10. При желании проверьте историю фиксации, чтобы убедиться, что все выглядит хорошо:

    $ svn log -r 1:HEAD
    

    Затем вернитесь на один уровень вверх:

    $ cd ..
    
  11. Дамп репозитория:

    $ svnadmin dump svn/project > project.dump
    
  12. И загрузите дамп на ваш сервер Subversion. Выполнено!

Этот процесс, вероятно, также будет работать напрямую между удаленными репозиториями, но мне было проще работать с локальными. Исправление времени коммита было большой работой, но в целом процесс был намного проще, чем любой другой метод, который я нашел.

Индрек
источник
1

Есть три метода:

  1. rebase : как и другие ответы

  2. id фиксации: найдите svn id первого коммита и git id первого коммита, выведите их в .git / info / grafts:echo "git_id svn_id}" > .git/info/grafts затемgit svn dcommit

  3. проверять каждый git коммит, копировать файлы в svn_repo, svn commit

демо bash: github demo

v1.x : используйте rebase и передайте id

v2.x: используйте копировать файлы, затем SVN-коммит

张耀文
источник
0

В моем случае мне пришлось инициировать чистый проект из SVN

$ Project> git svn init protocol://path/to/repo -s
$ Project> git svn fetch

добавить все источники вашего проекта ...

$ Project> git add .
$ Project> git commit -m "Importing project sources"
$ Project> git svn dcommit
dangt85
источник
0

Я просто хочу поделиться своим опытом с принятым ответом. Я сделал все шаги, и все было хорошо, прежде чем я выполнил последний шаг:

git svn dcommit

$ git svn dcommit

Использование неинициализированного значения $ u в подстановке (s ///) в строке /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 101.

Используйте неинициализированное значение $ u в конкатенации (.) Или строку в /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm строка 101. refs / remotes / origin / HEAD: ' https://192.168.2.101/ svn / PROJECT_NAME 'не найден в' '

Я нашел ветку https://github.com/nirvdrum/svn2git/issues/50 и, наконец, решение, которое я применил в следующем файле в строке 101 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm.

Я заменил

$u =~ s!^\Q$url\E(/|$)!! or die

с

if (!$u) {
    $u = $pathname;
} 
else {
       $u =~ s!^\Q$url\E(/|$)!! or die
      "$refname: '$url' not found in '$u'\n";
}

Это исправило мою проблему.

Павел Слепянкоу
источник
-1

Что делать, если вы не хотите совершать каждый коммит, который вы делаете в Git, в репозиторий SVN? Что если вы просто хотите выборочно отправлять коммиты по каналу? Ну, у меня есть лучшее решение.

Я держу один локальный репозиторий Git, где все, что я когда-либо делаю, это выборка и слияние из SVN. Таким образом, я могу убедиться, что я включаю все те же изменения, что и в SVN, но я полностью храню свою историю коммитов и SVN.

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

Когда я готов зафиксировать состояние моего локального Git-репозитория в SVN, я просто копирую весь беспорядок файлов в локальную рабочую копию SVN и фиксирую его оттуда, используя SVN, а не Git.

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

CommaToast
источник