git-svn: jaki jest odpowiednik `svn switch --relocate`?

88

Repozytorium svn, które dubluję przez git-svn, zmieniło adres URL.

W Vanilla SVN po prostu byś to zrobił svn switch --relocate old_url_base new_url_base.

Jak mogę to zrobić za pomocą git-svn?

Po prostu zmiana adresu URL svn w pliku konfiguracyjnym kończy się niepowodzeniem.

kch
źródło
Powinieneś spróbować i ewentualnie zaakceptować tę odpowiedź: stackoverflow.com/a/4061493/1221661
Fritz
Najbardziej aktualna odpowiedź: stackoverflow.com/a/40523789/537554 . To samo pytanie, ale zadane z perspektywy użytkownika Git.
ryenus

Odpowiedzi:

61

To całkiem dobrze rozwiązuje moją sytuację:

https://git.wiki.kernel.org/index.php/GitSvnSwitch

Sklonowałem za pomocą file://protokołu i chciałem przełączyć się na http://protokół.

Kuszące jest edytowanie urlustawienia w [svn-remote "svn"]sekcji .git/config, ale samo to nie działa. Ogólnie musisz postępować zgodnie z następującą procedurą:

  1. Przełącz ustawienie svn-remote urlna nową nazwę.
  2. Biegnij git svn fetch. To musi pobrać co najmniej jedną nową wersję z svn!
  3. Zmień ustawienie svn-remote z urlpowrotem na oryginalny adres URL.
  4. Uruchom, git svn rebase -laby wykonać lokalną rebase (ze zmianami wprowadzonymi podczas ostatniej operacji pobierania).
  5. Zmień ustawienie svn-remote z urlpowrotem na nowy adres URL.
  6. Teraz git svn rebasepowinno znowu działać.

Dusze żądne przygód mogą chcieć spróbować --rewrite-root.

kch
źródło
2
szczerze mówiąc, to się dla mnie nie powiodło i skończyło się na ponownym klonowaniu repozytorium. Trudno jest zmusić gita do obsługi tego, gdy zmienia się nazwa katalogu svn.
Gregg Lind
Wolałbym zaakceptować bardziej szczegółowy opis, ale w porządku, zaakceptuję go, dopóki nie pojawi się nowa odpowiedź.
kch
2
Oto kolejny opis tej procedury: theadmin.org/articles/git-svn-switch-to-a-different-a-svn-url
n8gray
link podany w zaakceptowanej odpowiedzi jest nieaktualny, a nowy jak na razie to: git.wiki.kernel.org/articles/g/i/t/GitSvnSwitch_8828.html. Postępowałem zgodnie z „Ogólnym przypadkiem” i było proste i naprawdę działało dobrze.
TcMaster
2
@TcMaster: dla mnie też zadziałało ... ale dlatego odpowiedzi nie powinny zawierać tylko linków, stają się nieaktualne i stają się bezużyteczne ... Zamierzam dodać odpowiedź wiki społeczności.
UncleZeiv
37

Możesz sprawdzić, czy poniższe elementy działają poprawnie:

  1. Jeśli svn-remote.svn.rewriteRootnie istnieje w pliku konfiguracyjnym ( .git/config):

    git config svn-remote.svn.rewriteRoot <currentRepositoryURL>
    
  2. Jeśli svn-remote.svn.rewriteUUIDnie istnieje w pliku konfiguracyjnym:

    git config svn-remote.svn.rewriteUUID <currentRepositoryUUID>
    

    currentRepositoryUUIDMożna otrzymać z .git/svn/.metadata.

  3. git config svn-remote.svn.url <newRepositoryURL>

H Krishnan
źródło
Fantastycznie - dzięki, to zadziałało świetnie (sklonowane przez file://, przełącz na svn+ssh); wystarczy zauważyć, że: ta procedura nie musi "pobierać co najmniej jednej nowej wersji z svn"; również ./.git/svn/.metadatapo pierwszym svn rebasezawiera <newRepository>as reposRoot- ale to nie wystarczy, aby usunąć rewrite*klucze .git/config; dlatego te klucze powinny być tam na stałe, o ile rozumiem.
sdaau
1
Na mnie też zadziałało, jak urok. OP powinien wypróbować ten i otrzymać poprawną odpowiedź.
Rafareino
Idealny. Miałem duży projekt z tysiącami zatwierdzeń w historii, więc nowy klon zniszczyłby historię (lub kasowanie zajęłoby naprawdę dużo czasu). Używam, svn+ssh://a nasz serwer svn właśnie zmienił domenę z .sena, .comaby oczyścić nasze wewnętrzne nazewnictwo.
UlfR
Zrobił mi przyjemność. Mając 2-letnie repozytorium z tysiącami zatwierdzeń, repozytorium zostało przeniesione na nowego hosta, więc uniknięto (przerażającego) pełnego klonu svn.
David Victor
21

Niestety większość linków w tych odpowiedziach nie działa, więc zamierzam zduplikować część informacji z git wiki na przyszłość.

To rozwiązanie zadziałało dla mnie:

  • Edytuj svn-remote url(lub fetchścieżkę) w, .git/configaby wskazać nową domenę / adres URL / ścieżkę

  • Uruchom git git svn fetch. To musi pobrać co najmniej jedną nową wersję z svn!

  • Jeśli spróbujesz git svn rebaseteraz, zostanie wyświetlony następujący komunikat o błędzie:

    Unable to determine upstream SVN information from working tree history
    

    Myślę, że dzieje się tak, ponieważ git svnjest zdezorientowany faktem, że ostatnie zatwierdzenie przed pobraniem będzie miało git-svn-idwskazanie na starą ścieżkę, która nie pasuje do tej znalezionej w .git/config.

  • Aby obejść ten problem, zmień svn-remote url(lub fetchścieżkę) z powrotem do oryginalnej domeny / adresu URL / ścieżki

  • Teraz uruchom git svn rebase -lponownie, aby wykonać lokalną rebase ze zmianami wprowadzonymi podczas ostatniej operacji pobierania. Tym razem to będzie działać, bo widocznie git svnnie należy mylić z faktu, że git-svn-idod nowego szefa nie zgadza się z tym znaleźć w .git/config.

  • Na koniec zmień svn-remote url(lub fetchścieżkę) z powrotem do nowej domeny / adresu URL / ścieżki

  • W tym momencie git svn rebasepowinno działać ponownie!

Oryginalne informacje zostały znalezione tutaj .

UncleZeiv
źródło
3

Git svn w dużym stopniu opiera się na adresie URL svn. Każde zatwierdzenie, które jest importowane z svn git-svn-id, zawiera adres URL svn.

Prawidłową strategią relokacji jest zadzwonienie git-svn clone nowego repozytorium i połączenie zmian z tym nowym zamknięciem. Aby uzyskać bardziej szczegółową procedurę, zobacz ten artykuł:

http://www.sanityinc.com/articles/relocating-git-svn-repositories

Adam Alexander
źródło
2

git filter-branch

Ten skrypt , zaczerpnięty z wpisu na blogu , zadziałał dla mnie. Podaj stary i nowy adres URL repozytorium jako parametr, tak jak w przypadku svn switch --relocate.

Skrypt wywołuje git filter-branchzastąpienie adresów URL Subversion w git-svn-idkomunikatach o zmianach .git/config, aktualizuje , a także aktualizuje git-svnmetadane, odtwarzając je za pomocą git svn rebase. Chociaż git svn clonemoże być bardziej niezawodnym rozwiązaniem, filter-branchpodejście to działa znacznie szybciej w przypadku dużych repozytoriów (godziny w porównaniu z dniami).

#!/bin/sh

# Must be called with two command-line args.
# Example: git-svn-relocate.sh http://old.server https://new.server
if [ $# -ne 2 ]
then
  echo "Please invoke this script with two command-line arguments (old and new SVN URLs)."
  exit $E_NO_ARGS
fi

# Prepare URLs for regex search and replace.
oldUrl=`echo $1 | awk '{gsub("[\\\.]", "\\\\\\\&");print}'`
newUrl=`echo $2 | awk '{gsub("[\\\&]", "\\\\\\\&");print}'`

filter="sed \"s|^git-svn-id: $oldUrl|git-svn-id: $newUrl|g\""
git filter-branch --msg-filter "$filter" -- --all

sed -i.backup -e "s|$oldUrl|$newUrl|g" .git/config

rm -rf .git/svn
git svn rebase
krlmlr
źródło
1

git_fast_filter

Jednak szybciej niż git-filter-branch(tj. Minuty zamiast godzin), ale podobnie w duchu, jest użycie git_fast_filter. Wymaga to jednak nieco więcej kodowania i nie istnieje żadne schludne, gotowe rozwiązanie. W przeciwieństwie do git-filter-branchtego spowoduje to utworzenie nowego repozytorium ze starego . Zakłada się, że masterwskazuje na ostatnie zatwierdzenie SVN.

  1. Klon git_fast_filterz repo Gitorious.
  2. Utwórz skrypt Pythona w tym samym katalogu, w którym sklonowałeś git_fast_filterna podstawie tego Gist , ustaw wykonywalny bit za pomocą chmod +x. Dostosuj stare i nowe ścieżki repozytorium. (Treść skryptu jest również wklejona poniżej).
  3. Zainicjuj nowe repozytorium docelowe za pomocą git init, zmień katalog roboczy na to nowe repozytorium.
  4. Wykonaj następującą potokę:

    (cd path/to/old/repo && git-fast-export --branches --tags --progress=100) | \
        path/to/git_fast_filter/commit_filter.py | git-fast-import
    
  5. Skopiuj .git/configi być może inne odpowiednie pliki w formacie.git/info ze starego repozytorium do nowego repozytorium.

  6. Usuń .git/svn.
  7. Zwróć uwagę git-svnna nowe mapowanie numerów wersji

    1. Wykonać git branch refs/remotes/git-svn master

      • Twoje piloty git-svn można nazwać inaczej niż refs/remotes/git-svnskonsultować .git/config, svn-remotesekcje
    2. Wykonaj git svn info. Jeśli to polecenie zawiesza się, coś jest nie tak. Powinien odbudować mapowanie numerów wersji.

    3. Usuń fałszywą gałąź refs/remotes/git-svn, zostanie odtworzona przezgit-svn

  8. Synchronizuj, dzwoniąc git svn rebase.

Poniżej znajduje się treść commit_filter.py, zamień wartości IN_REPOi OUT_REPOodpowiednio:

#!/usr/bin/python

from git_fast_filter import Commit, FastExportFilter
import re
import sys

IN_REPO = "https://svn.code.sf.net/p/matsim/code"
OUT_REPO = "https://svn.code.sf.net/p/matsim/source"

IN_REPO_RE = re.compile("^git-svn-id: %s" % re.escape(IN_REPO), re.M)
OUT_REPO_RE = "git-svn-id: %s" % OUT_REPO

def my_commit_callback(commit):
  commit.message = IN_REPO_RE.sub(OUT_REPO_RE, commit.message)
  sys.stderr.write(".")

filter = FastExportFilter(commit_callback = my_commit_callback)
filter.run()
krlmlr
źródło
0

Powyższe git svn rebase -lrozwiązanie u mnie nie działa. Postanowiłem zająć się tym inaczej:

  1. Sklonuj stare repozytorium SVN do repozytorium git, olda nowe repozytorium SVN do repozytorium gitnew
  2. Pobierz olddonew
    • cd new
    • git fetch ../old
    • git tag old FETCH_HEAD
  3. Rebase newna szczycie old(powinno się powieść, ponieważ drzewa w korzeniu newi na końcu oldsą identyczne)
    • git checkout master(Zakłada się, że mastergałąź wskazuje na główkę SVN. Tak będzie w przypadku czystego klonu; w przeciwnym razie dcommit przed rozpoczęciem).
    • git rebase --root --onto old
  4. Przebuduj metadane git-svn z, newaby uwzględnić rebase
    • git update-ref --no-deref refs/remotes/git-svn master(dostosuj zdalny numer referencyjny w zależności od tego, jak sklonowałeś, np. może to być refs/remotes/svn/trunk)
    • rm -r .git/svn
    • git svn info
Ben Challenor
źródło
1. Czy zaczynasz od nowego sklonowania nowej lokalizacji do nowej? Jeśli tak, dlaczego nie skończyłeś w tym momencie? 2. Jeśli ponownie bazujesz na nowych na starych, czy wszystkie stare zatwierdzenia wspominają o starym adresie URL w swoim wpisie dziennika zatwierdzeń svn-id? 3. Czy jest jakaś dokumentacja, którą należy zapisać, aby usunąć plik .git / svn? (3b: które polecenie odbudowuje metadane git-svn, git svn info?)
Micha Wiedenmann
0

Opierając się na niektórych innych odpowiedziach na to pytanie, wymyśliłem skrypt Ruby, który obsługuje relokację git-svn. Możesz go znaleźć na https://gist.github.com/henderea/6e779b66be3580c9a584 .

Obsługuje relokację bez sprawdzania innej kopii, a nawet obsługuje przypadek, w którym występują niewysłane zmiany w jednej lub kilku gałęziach (ponieważ łamie to zwykłą logikę). Używa rzeczy z odpowiedzi git filter-branch (dla głównej logiki) i odpowiedzi o kopiowaniu gałęzi z jednej instancji repozytorium do drugiej (do kopiowania gałęzi z niezapchniętymi zmianami).

Używałem tego do przenoszenia kilku repozytoriów git-svn, które mam do pracy, a ta wersja skryptu (przeszedłem przez niezliczone iteracje) wydaje się działać dla mnie. Nie jest superszybki, ale wydaje się obsługiwać wszystkie napotkane przypadki i skutkować w pełni przeniesionym repozytorium.

Skrypt daje możliwość utworzenia kopii repozytorium przed wprowadzeniem jakichkolwiek zmian, więc można użyć tej opcji do utworzenia kopii zapasowej. Utworzenie kopii jest wymagane, jeśli masz cofnięte zmiany w jakichkolwiek gałęziach.

Skrypt nie używa żadnych klejnotów ani innych bibliotek, które nie są zawarte w normalnej instalacji MRI Ruby. Używa bibliotek readline i fileutils zawartych w MRI.

Mam nadzieję, że mój skrypt przyda się komuś innemu. Zapraszam do wprowadzania zmian w skrypcie.

UWAGA: Testowałem ten skrypt tylko z git 2.3.0 / 2.3.1 i Ruby 2.2.0 na OS X 10.10 Yosemite (ponieważ jest to środowisko, którego używam), ale spodziewałbym się, że będzie działał również w innych środowiskach. Nie ma jednak gwarancji dotyczących systemu Windows.

Eric Henderson
źródło