Przekazywanie istniejącego repozytorium Git do SVN


384

Całą swoją pracę wykonywałem w Git i naciskałem na GitHub. Jestem bardzo zadowolony zarówno z oprogramowania, jak i strony, i nie chcę w tym momencie zmieniać moich praktyk pracy.

Mój doradca doktorski prosi wszystkich studentów o zachowanie pracy w repozytorium SVN, które jest hostowane na uniwersytecie. Znalazłem mnóstwo dokumentacji i samouczków na temat ściągania istniejącego repozytorium SVN do Git, ale nic o pchaniu repozytorium Git do świeżego repozytorium SVN. Spodziewam się, że musi być jakiś sposób na połączenie git-svn ze świeżą gałęzią, rebasingiem i wszystkimi tymi cudownymi warunkami, ale jestem początkującym Gitem i nie czuję się pewnie w żadnym z nich.

Następnie chcę po prostu uruchomić kilka poleceń, aby wypchnąć zatwierdzenia do tego repozytorium SVN, kiedy zdecyduję. Chcę nadal używać Git i po prostu mieć lustro repozytorium SVN, co jest w Git.

Będę jedyną osobą, która kiedykolwiek zaangażuje się w SVN, jeśli to coś zmieni.


1
Uwaga: po wykonaniu tej czynności prawdopodobnie stracisz swoje oryginalne znaczniki daty. Nowe daty będą oparte na czasie importu do Subversion.
nobar

Dla tych, którzy szukają bardziej aktualnych informacji, niektórzy mogą znaleźć następujący post podczas wyszukiwania automatyzacji: deliciousbrains.com/deploying-wordpress-plugins-travis
Josh Habdas

Odpowiedzi:


402

Potrzebowałem tego również i przy pomocy odpowiedzi Bombe + trochę błąkania się, udało mi się. Oto przepis:

Importuj 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

Po # 3 otrzymasz tajemniczą wiadomość:

Używając wyższego poziomu adresu URL: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

Zignoruj ​​to.

Po uruchomieniu nr 5 możesz mieć konflikty. Rozwiąż je, dodając pliki ze stanem „unmerged” i wznawiając rebase. W końcu skończysz; następnie zsynchronizuj z repozytorium SVN, używając dcommit. To wszystko.

Synchronizacja repozytoriów

Możesz teraz synchronizować z SVN do Git, używając następujących poleceń:

git svn fetch
git rebase trunk

Aby zsynchronizować dane z Git do SVN, użyj:

git svn dcommit

Ostatnia uwaga

Możesz wypróbować to na lokalnej kopii, zanim zastosujesz się do repozytorium na żywo. Możesz zrobić kopię swojego repozytorium Git w tymczasowym miejscu; po prostu użyj cp -r, ponieważ wszystkie dane znajdują się w samym repozytorium. Następnie można skonfigurować repozytorium testowe oparte na plikach, używając:

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

I sprawdź kopię roboczą, używając:

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

To pozwoli ci bawić się przedmiotami przed wprowadzeniem jakichkolwiek trwałych zmian.

Dodatek: Jeśli popsuniesz git svn init

Jeśli przypadkowo uruchomisz git svn initz niewłaściwym adresem URL i nie jesteś wystarczająco inteligentny, aby wykonać kopię zapasową swojej pracy (nie pytaj ...), nie możesz po prostu ponownie uruchomić tego samego polecenia. Możesz jednak cofnąć zmiany, wydając:

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

I usuń sekcję [svn-remote "svn"]sekcji.

Następnie możesz uruchomić od git svn initnowa.


2
Niezła odpowiedź. Czy to też psuje daty zatwierdzenia?
Drew Noakes

4
Dobre pytania - niestety nie znam odpowiedzi na żadne z nich. To jest bardziej praktyczny przewodnik po tym, co znalazłem do pracy. Nie do końca rozumiem wszystkie szczegóły. Jeśli chodzi o daty zatwierdzenia, myślę, że możesz zrobić test i się dowiedzieć. Pamiętaj, że możesz zainicjować lokalne (oparte na FS) repozytorium svn do testowania.
troelskn

10
Mam te same czynności, a następnie za pomocą „git rebase --onto bagażnik --root” zamiast kroku 5 i miał dużo więcej sukcesów. Tylko garść konfliktów scalania do rozwiązania, zamiast ton.
kubi

5
W moim przypadku ta sekwencja nie zadziałała. Zawsze wyświetlany był komunikat „Nie można ustalić informacji SVN w górę od historii HEAD”. Więc nie jest to możliwe.
Fedir RYKHTIK

2
Nieważne, starałem się być mądry i pominąłem -s, ponieważ nie chciałem postępować zgodnie ze standardową konfiguracją SVN (trunk / branch / tags /). Bez tego nie byłby w stanie działać.
James McMahon,

33

Oto, w jaki sposób sprawiliśmy, że działało:

Sklonuj swoje repozytorium Git gdzieś na komputerze.

Otwórz .git / config i dodaj następujące (z Utrzymania tylko lustro SVN repozytorium Git tylko do odczytu ):

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

Teraz w oknie konsoli wpisz:

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

Teraz, jeśli z jakiegoś powodu się zepsuje, wpisz te trzy wiersze:

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

I na koniec możesz zatwierdzić SVN:

git svn dcommit

Uwaga: zawsze później usuwam ten folder.


6
+1 to faktycznie działało dla mnie (nie mam bagażnika / bazy, cokolwiek), w przeciwieństwie do innych odpowiedzi, które ciągle Unable to determine upstream SVN information from HEAD history.
dawałem


2
Próbowałem tej techniki, ale nie importowała historii. Btw, „git merge master” to teraz „git merge - mistrz niepowiązanych historii”
Berend de Boer

1
Jeśli absolutnie chcesz zastąpić zawartość SVN tym, co jest w git, użyj git merge -s recursive -Xtheirs --allow-unrelated-histories master .
user1475814,

28

Użycie git rebasebezpośrednie spowoduje utratę pierwszego zatwierdzenia. Git traktuje to inaczej i nie może go zmienić.

Istnieje procedura, która zachowa pełną historię: http://kerneltrap.org/mailarchive/git/2008/10/26/3815034

Tutaj opiszę rozwiązanie, ale podziękowania należą się Björnowi.

Zainicjuj git-svn:

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

--Prefix daje zdalne gałęzie śledzące, takie jak „svn / trunk”, co jest miłe, ponieważ nie otrzymujesz niejednoznacznych nazw, jeśli nazywasz swój oddział lokalny tylko „trunk”. I -sjest skrótem dla standardowego bagażnika / tagów / Układ oddziałów.

Pobierz początkowe pliki z SVN:

git svn fetch

Teraz sprawdź hash twojego głównego zatwierdzenia (powinien pokazywać pojedynczy zatwierdzenie):

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

Następnie uzyskaj skrót pustego zatwierdzenia trunkingu:

git rev-parse svn/trunk

Utwórz przeszczep:

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

Teraz „gitk” powinien pokazywać się svn/trunkjako pierwszy zatwierdzenie, na którym oparta jest twoja gałąź master.

Uczyń przeszczep trwałym:

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

Upuść przeszczep:

rm .git/info/grafts

gitk powinien nadal pokazywać svn/trunk w przodkach mistrza.

Zlinearyzuj swoją historię nad bagażnikiem:

git svn rebase

A teraz „git svn dcommit -n” powinien powiedzieć ci, że zobowiązuje się do trunkingu.

git svn dcommit

Czy możesz wyjaśnić, w jaki sposób ta technika różni się od powyższej, wyraźniej.
cmcginty,

3
Kiedy próbuję „git rev-parsować svn / trunk” zgłasza nieznaną wersję lub ścieżkę nie w działającym drzewie.
Adam Ness,

To jest jedyna odpowiedź, która zadziałała dla mnie, oprócz tego, że kroki git filter-branch i drop graft nie były potrzebne: zrobiłem bazę po utworzeniu graftu, a potem zrobiłem git svn dcommit.
fc7

8

Utwórz nowy katalog w repozytorium Subversion dla swojego projektu.

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

Przejdź do projektu zarządzanego przez Git i zainicjuj git-svn.

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

Spowoduje to utworzenie pojedynczego zatwierdzenia, ponieważ katalog projektu SVN jest nadal pusty. Teraz oprzyj wszystko na tym zatwierdzeniu git svn dcommiti powinieneś to zrobić. Poważnie zepsuje to jednak daty zatwierdzenia.


Użyłem tej odpowiedzi z instrukcjami na stronie hassox.blogspot.com/2007/12/using-git-with-svn.html Wykonałem te polecenia, a następnie „#git branch -a”, aby zobaczyć nazwę pnia. Następnie: # git checkout -b local-svn trunk # git merge master # git svn dcommit Pamiętaj o .gitignore katalogu .svn!
cflewis

Ponieważ właśnie wykonałem tę samą operację, chciałem wyraźnie powiedzieć, że od pewnego czasu (styczeń 2009 r.) Git może wykonywać operacje zmiany bazy na zatwierdzeniu głównym. To sprawia, że ​​proces jest znacznie prostszy, niż wskazuje wiele starych artykułów, patrz komentarze na its.arubything.com/2009/1/4/…
Louis Jacomet

Do czego służy opcja inicjalizacji „-s” git svn? Nie widzę tego na stronach podręcznika użytkownika git svn.
Nathan

Przeczytaj stronę podręcznika ponownie, być może wyszukaj „-s”, ponieważ ona tam jest. Jest to alias dla „--stdlayout”.
Bombe

7

Git -> SVN z pełną historią zatwierdzeń

Miałem projekt Git i musiałem go przenieść do SVN. Tak to zrobiłem, zachowując całą historię popełnień. Jedyne, co się gubi, to oryginalny czas zatwierdzenia, ponieważ libSVN ustawi czas lokalny, kiedy to zrobimy git svn dcommit.

Jak:

  1. Posiadamy repozytorium SVN, do którego chcemy zaimportować nasze rzeczy i sklonować je za pomocą git-svn:

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. Idź tam:

    cd repo.git-svn
    
  3. Dodaj zdalne repozytorium Git (w tym przykładzie używam C: /Projects/repo.git ). Chcesz przesłać do SVN i nadać mu nazwę old-git:

    git remote add old-git file:///C/Projects/repo.git/
    
  4. Pobierz informacje z gałęzi master ze starego repozytorium git do bieżącego repozytorium:

    git fetch old-git master
    
  5. Kasa master oddziału zdalnego starego gita do nowej gałęzi o nazwie old w bieżącym repozytorium:

    git checkout -b old old-git/master`
    
  6. Rebase, aby umieścić HEAD na old-git / master. Pozwoli to zachować wszystkie twoje zobowiązania. To w zasadzie polega na tym, aby wziąć całą swoją pracę wykonaną w Git i umieścić ją na wierzchu pracy, do której uzyskujesz dostęp z SVN.

    git rebase master
    
  7. Teraz wróć do głównej gałęzi:

    git checkout master
    

    I widać, że masz czystą historię zatwierdzeń. Właśnie to chcesz przekazać do SVN.

  8. Przekaż swoją pracę do SVN:

    git svn dcommit
    

To wszystko. Jest bardzo czysty, nie hakuje, a wszystko działa idealnie po wyjęciu z pudełka. Cieszyć się.


Podobny proces opisano również na chani.wordpress.com/2012/01/25/…
TWiStErRob

Wygląda jak. Jednak jej sposób jest dość mylący, a mój jest znacznie krótszy (8 kroków niż 19/23). Może nie rozumiem jej poprawnie, ale myślę, że w drugiej kuli miesza polecenia svn i git.
codingdave

Ach, tak, różnica polega na tym, że twój proces importuje git do katalogu głównego repozytorium SVN, a jej importuje go do podfolderu, dlatego git svnpotrzebnych jest kilka wstępnych wersji.
TWiStErRob,

Czy w kroku 7 nie powinno być starego połączenia git? Wydaje mi się, że robisz komendę mistrza, której nie zmieniłeś ?!
Alexander

@Alexander za pomocą 'git rebase master' dajemy szybkie przewijanie do przodu, to znaczy łączenie liniowe bez zatwierdzenia scalania mającego dwoje rodziców. Chcemy mieć tutaj liniową historię.
codingdave


3

Musiałem zatwierdzić moje istniejące repozytorium Git w pustym repozytorium SVN.

Tak udało mi się to zrobić:

$ 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

Działa bez problemów. Mam nadzieję, że to komuś pomoże.

Ponieważ musiałem się autoryzować przy użyciu innej nazwy użytkownika niż repozytorium SVN (moje originuwierzytelnianie przy użyciu klucza prywatnego / publicznego), musiałem użyć tej --usernamewłaściwości.


może być konieczna instalacja, git-svnzanim będzie to możliwe, zobacz stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive

2

Jeśli chcesz kontynuować pracę z Git jako głównym repozytorium i od czasu do czasu musisz tylko „eksportować” wersje do SVN, możesz użyć programu Tailor, aby utrzymać synchronizację repozytorium SVN. Może kopiować wersje między różnymi systemami kontroli źródła i aktualizowałby SVN o zmiany wprowadzone w Git.

Nie próbowałem konwersji Git-SVN, ale dla przykładu SVN -> SVN zobacz tę odpowiedź .


2

Kolejna sekwencja, która zadziałała (z pewnymi komentarzami na każdym etapie):

  1. Zainstaluj git-svni subversionzestawy narzędzi:

    sudo apt-get install git-svn subversion
    
  2. Przełącz wewnątrz PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. Utwórz ścieżkę projektu na serwerze Subversion (niestety obecna git-svnwtyczka ma wadę w porównaniu z TortoiseSVN). Nie można przechowywać kodu źródłowego bezpośrednio w PROJECT_FOLDER. Zamiast tego domyślnie prześle cały kod do PROJECT_FOLDER/trunk.

    svn mkdir - protokół rodziców: /// ścieżka / do / repo / PROJECT_FOLDER / trunk -m "tworzenie symbolu zastępczego git repo"

Jest to miejsce, w którym trunkna końcu ścieżki jest obowiązkowe

  1. Zainicjuj git-svnkontekst wtyczki w .gitfolderze

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

    To miejsce, w którym trunkna końcu ścieżki nie jest konieczne

  2. Pobierz puste Subversioninformacje o repozytorium

    git svn fetch
    

    Ten krok pomaga zsynchronizować serwer Subversion z git-svnwtyczką. Jest to moment, w którym git-svnwtyczka ustala remotes/originścieżkę i kojarzy ją z trunkpodfolderem po stronie serwera.

  3. Rebase stare zatwierdzenia Git wydarzyły się zanim git-svnwtyczka zaangażowała się w ten proces (ten krok jest opcjonalny )

    git rebase origin/trunk
    
  4. Dodaj nowe / zmodyfikowane pliki do zatwierdzenia (ten krok jest regularny dla działań Git i jest opcjonalny )

    git add .
    
  5. Zatwierdź świeżo dodane pliki do lokalnego repozytorium Git (ten krok jest opcjonalny i ma zastosowanie tylko wtedy, gdy zastosowano krok 7):

    git commit -m "Importing Git repository"
    
  6. Przekazanie całej historii zmian projektu do serwera Subversion:

    git svn dcommit
    

1

Możesz utworzyć nowe repozytorium SVN. Wyeksportuj swój projekt Git (rozwijając pliki .git). Dodaj go do repozytorium SVN (inicjowanie repozytorium z tym, co do tej pory miałeś w Git). Następnie skorzystaj z instrukcji importowania repozytoriów SVN w nowym projekcie Git.

Spowoduje to jednak utratę poprzedniej historii Git.



1

Chciałbym udostępnić świetne narzędzie używane w społeczności WordPress o nazwie Scatter

Wtyczki Git WordPress i odrobina rozsądku

Dzięki temu użytkownicy mogą automatycznie wysyłać swoje repozytorium Git do wordpress.org SVN. Teoretycznie ten kod można zastosować do dowolnego repozytorium SVN.


Wydaje się, że łącze zostało skutecznie zerwane ( „Serwer w witrynie evansolomon.me odpowiada zbyt długo” ).
Peter Mortensen

1

Niedawno musiałem przeprowadzić migrację kilku repozytoriów Git do SVN i po wypróbowaniu wszystkich rozwiązań, jakie udało mi się znaleźć, w końcu zadziałał Mercurial (tak, używając trzeciego VCS). Korzystając z tego przewodnika , wymyśliłem następujący proces (w systemie Linux, ale podstawowy pomysł powinien również działać w systemie Windows).

  1. Niezbędne pakiety:

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. Mercurial należy skonfigurować, dodając następujące elementy do ~/.hgrc:

    [extensions]
    hgext.convert=
    
  3. Utwórz tymczasowe katalogi robocze (miałem do migracji kilka repozytoriów, więc utworzyłem katalogi dla wersji SVN i Git, aby je rozdzielić):

    $ mkdir svn
    $ mkdir git
    
  4. Utwórz puste lokalne repozytorium SVN:

    $ svnadmin create svn/project
    
  5. Sklonuj istniejące repozytorium Git:

    $ git clone server/path/project.git git/project
    
  6. Niech Mercurial zrobi to samo:

    $ hg convert --dest-type svn git/project svn/project
    
  7. Teraz repozytorium SVN powinno zawierać pełną historię zatwierdzeń, ale nie powinno zawierać oryginalnych znaczników czasu. Jeśli to nie jest problem, przejdź do następnej części do kroku 11.

  8. Przy odrobinie pracy można zmienić datę i godzinę każdego zatwierdzenia . Ponieważ moje repozytoria są dość małe, wykonałem to ręcznie. Najpierw utwórz pre-revprop-changehak w repozytorium SVN z następującą zawartością, aby umożliwić modyfikację niezbędnych właściwości:

    #!/bin/bash
    exit 0;
    

    Ten skrypt musi być wykonywalny:

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial utworzył kopię roboczą repozytorium SVN o nazwie project -wc, więc przejdź do niego i edytuj czasy zatwierdzenia:

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

    Wprowadź poprawną datę i godzinę (zwróć uwagę na strefy czasowe!) I oszczędzaj. Powinien zostać wyświetlony komunikat „Ustaw nową wartość dla właściwości svn: data w wersji 1”.
    Teraz spłucz i powtórz dla każdej innej wersji.

  10. Opcjonalnie sprawdź historię zatwierdzeń, aby upewnić się, że wszystko wygląda OK:

    $ svn log -r 1:HEAD
    

    Następnie wróć o jeden poziom wyżej:

    $ cd ..
    
  11. Zrzuć repozytorium:

    $ svnadmin dump svn/project > project.dump
    
  12. I załaduj zrzut na swoim serwerze Subversion. Gotowy!

Ten proces prawdopodobnie działałby również bezpośrednio między zdalnymi repozytoriami, ale łatwiej mi było pracować z lokalnymi. Naprawianie czasów zatwierdzania było dużym nakładem pracy, ale ogólnie proces był znacznie prostszy niż w przypadku każdej innej metody, którą znalazłem.


1

istnieją trzy metody :

  1. rebase : jak inne odpowiedzi

  2. commit id: znajdź svn first commit id i git first commit id, echo ich do .git / info / grafts: echo "git_id svn_id}" > .git/info/graftsnastępniegit svn dcommit

  3. kasy każde zatwierdzenie git, skopiuj pliki do svn_repo, svn commit

demo bash dem demo github

v1.x : użyj rebase i zatwierdzenia id

v2.x: użyj kopiowania plików, a następnie svn commit


0

W moim przypadku musiałem zainicjować czysty projekt z SVN

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

dodaj wszystkie źródła projektu ...

$ Project> git add .
$ Project> git commit -m "Importing project sources"
$ Project> git svn dcommit

0

Chcę tylko podzielić się niektórymi doświadczeniami z zaakceptowaną odpowiedzią. Zrobiłem wszystkie kroki i wszystko było w porządku, zanim wykonałem ostatni krok:

git svn dcommit

$ git svn dcommit

Zastosowanie niezainicjowanej wartości $ u w podstawieniu (s ///) w linii /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm

Zastosowanie niezainicjowanej wartości $ u w konkatenacji (.) Lub ciągu w /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm wiersz 101. refs / remotes / origin / HEAD: ' https://192.168.2.101/ nie znaleziono svn / PROJECT_NAME w „”

Znalazłem wątek https://github.com/nirvdrum/svn2git/issues/50 i wreszcie rozwiązanie, które zastosowałem w następującym pliku w linii 101 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm

Wymieniłem

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

z

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

To naprawiło mój problem.


-1

Co jeśli nie chcesz zatwierdzać każdego zatwierdzenia dokonanego w Git do repozytorium SVN? Co jeśli chcesz tylko selektywnie wysyłać zatwierdzenia potoku? Cóż, mam lepsze rozwiązanie.

Mam jedno lokalne repozytorium Git, w którym wszystko, co kiedykolwiek robię, to pobieranie i łączenie z SVN. W ten sposób mogę się upewnić, że uwzględniam wszystkie te same zmiany co SVN, ale całkowicie trzymam moją historię zatwierdzeń od SVN.

Następnie przechowuję osobną lokalną kopię roboczą SVN, która znajduje się w osobnym folderze. Właśnie z tego robię zatwierdza z powrotem do SVN i po prostu używam do tego narzędzia wiersza poleceń SVN.

Kiedy jestem gotowy, aby przekazać stan mojego lokalnego repozytorium Git do SVN, po prostu kopiuję cały bałagan plików do lokalnej kopii roboczej SVN i stamtąd zatwierdzam go za pomocą SVN zamiast Git.

W ten sposób nigdy nie muszę robić żadnego bazowania, ponieważ bazowanie jest jak freebasing.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.