Переміщення наявного сховища Git до SVN


384

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

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

Тоді я хочу просто виконати пару команд, щоб натиснути коміти до цього сховища SVN, коли я виберу. Я хочу продовжувати використовувати Git і просто мати дзеркало сховища SVN, що є в Git.

Я буду єдиною людиною, яка коли-небудь здійснює SVN, якщо це має значення.


1
Зверніть увагу: коли ви це зробите, ви, можливо, втратите свої оригінальні відмітки. Нові дати ґрунтуватимуться на часі імпорту до Subversion.
nobar

Для тих, хто шукає більш актуальну інформацію, деякі можуть знайти наступну публікацію корисною під час їх автоматичного пошуку: deliciousbrains.com/deploying-wordpress-plugins-travis
Josh Habdas

Відповіді:


402

Мені це потрібно було і мені, і за допомогою відповіді Бомбе + трохи обмацуючи, я працював. Ось рецепт:

Імпорт 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 у вас можуть виникнути конфлікти. Вирішіть їх, додавши файли із станом "без вимикання" та відновлення відновлення. Врешті-решт, ви закінчите; потім синхронізуйте назад до сховища 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заново.


2
Гарна відповідь. Чи це також зіпсує дати вчинення?
Дрю Ноакс

4
Хороші запитання - На жаль, я не знаю відповіді на жодне. Це більше практичне керівництво того, що я знайшов працювати. Я не повністю розумію всі деталі. Щодо дати фіксації, я думаю, ви могли б зробити тест і дізнатися. Пам’ятайте, що для тестування речей ви можете запросити локальну (на основі fs) svn repo.
troelskn

10
Я виконував ці ж кроки, використовуючи "git rebase --onto trunk --root" замість кроку 5 і мав набагато більший успіх. Вирішити лише кілька конфліктів злиття, а не тонни.
кубі

5
У моєму випадку ця послідовність не працювала. Завжди було показано повідомлення "Неможливо визначити інформацію SVN за течією з історії HEAD". Таким чином, жоден dcommit неможливий.
Федір РИХТИК

2
Незважаючи на те, я намагався зробити розумним і опустити -s, оскільки я не хотів дотримуватися стандартних налаштувань SVN (магістраль / гілки / теги /). Не могло без цього взагалі працювати.
Джеймс Макмахон

33

Ось як ми це зробили:

Клоніруйте своє сховище Git десь на вашій машині.

Відкрийте .git / config та додайте наступне (із підтримання дзеркала, доступного лише для читання, у сховищі 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.
вдень

2
Ще один приємний підсумок: codeography.com/2010/03/17/howto-mirror-git-to-subversion.html
Томмі

2
Я спробував цю техніку, але вона не імпортувала історію. Btw, "git merge master" now is "git merge --allow-nepovezano-istories master"
Berend de Boer

1
Якщо ви абсолютно хочете замінити те, що в SVN, тим, що знаходиться в git, використовуйте git merge -s recursive -Xtheirs --allow-unrelated-histories master.
користувач1475814

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

gitk все одно повинен показати 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 гілка -а", щоб побачити ім'я стовбура. Потім: # git checkout -b local-svn trunk # git merge master # git svn dcommit Не забудьте .gitignore каталог .svn!
cflewis

Оскільки я щойно робив ту саму операцію, я хотів би пояснити, що деякий час (січень '09) git може виконувати операцію ребаїнгу на кореневій комісії. Це робить процес набагато простішим, ніж багато старих статей вказують, дивіться коментарі до його. Arubything.com/2009/1/4/…
Луї Якомет

Що робить опція "-s" git svn init? Я не бачу цього на сторінках man для git svn.
Натан

Прочитайте знову сторінку чоловіка, можливо, знайдіть "-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. Отримати інформацію з ведучої гілки зі сховища old-git до поточного сховища:

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

    git checkout -b old old-git/master`
    
  6. База, щоб поставити HEAD поверх old-git / master. Це дозволить підтримувати всі ваші зобов'язання. Це в основному полягає в тому, щоб взяти всю свою роботу в Git і помістити її над роботою, до якої ви звертаєтесь з SVN.

    git rebase master
    
  7. Тепер поверніться до вашого головного відділення:

    git checkout master
    

    І ви бачите, що у вас є чиста історія фіксації. Це те, що ви хочете підштовхнути до SVN.

  8. Надішліть свою роботу до SVN:

    git svn dcommit
    

Це все. Він дуже чистий, без злому, і все прекрасно працює поза коробкою. Насолоджуйтесь.


Подібний процес також детально описаний на chani.wordpress.com/2012/01/25/…
TWiStErRob

Виглядає як. Однак я вважаю її шлях досить заплутаним, і мій набагато коротший (8 кроків, ніж 19/23). Можливо, я не розумію її правильно, але я думаю, що вона змішує команди svn та git у своїй другій кулі.
кодування

Ага, так, різниця полягає в тому, що ваш процес імпортує git до кореня репортажу SVN, він імпортує його в підпапку, тому для цього потрібно декілька git svnпреп.
TWiStErRob

На кроці 7, чи не повинно бути старого злиття git? Мені здається, ти робиш домовленість господаря, яку ти не змінив ?!
Олександр

@Alexander, використовуючи 'git rebase master', ми отримуємо швидке злиття вперед, тобто лінійне злиття без злиття, яке має двох батьків. Ми хочемо мати тут лінійну історію.
codingdave


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 дивіться цю відповідь .


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 - протоколparentparents: /// шлях / до / repo / PROJECT_FOLDER / trunk -m "створення git repo placeholder"

Це місце, де 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


SVN що? В ( "... будь-який конкретний SVN і ..." ). SVN-версія? SVN-клієнт? Або щось інше?
Пітер Мортенсен

1

Я хотів би поділитися чудовим інструментом, який використовується у спільноті WordPress під назвою Scatter

Git WordPress плагіни і трохи розуму розсипаються

Це дає можливість користувачам автоматично надсилати своє сховище Git до Wordpress.org SVN. Теоретично цей код можна застосувати до будь-якого сховища SVN.


Здається, посилання ефективно порушено ( "Сервер на 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. Нехай Меркуріал робить свою справу:

    $ 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: дата перегляду 1".
    Тепер промийте та повторіть для кожної іншої редакції.

  10. За бажанням перевірте історію фіксації, щоб переконатися, що все виглядає нормально:

    $ svn log -r 1:HEAD
    

    Потім поверніться вгору на один рівень:

    $ cd ..
    
  11. Вивантажте сховище:

    $ svnadmin dump svn/project > project.dump
    
  12. І завантажте дамп на ваш сервер Subversion. Готово!

Цей процес, ймовірно, також буде працювати безпосередньо між віддаленими сховищами, але мені було легше працювати з локальними. Виправлення часів фіксації було багато роботи, але в цілому процес був набагато простішим, ніж будь-який інший метод, який я знайшов.


1

є три методи:

  1. rebase: як інші відповіді

  2. виконувати ідентифікатор: знайти svn спершу ідентифікатор і git спершу зробити ідентифікатор, повторити їх у .git / info / grafts: echo "git_id svn_id}" > .git/info/graftsthengit svn dcommit

  3. оформити кожен git-комітет, скопіюйте файли у svn_repo, svn

bash demo: github demo

v1.x: використовувати rebase і виконувати ідентифікатор

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

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/isissue/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.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.