Invio di un repository Git esistente a SVN


385

Ho fatto tutto il mio lavoro in Git e ho spinto in GitHub. Sono stato molto contento sia del software che del sito, e non desidero cambiare le mie pratiche di lavoro a questo punto.

Il mio consulente di dottorato chiede a tutti gli studenti di conservare il proprio lavoro in un repository SVN ospitato all'università. Ho trovato tonnellate di documentazione ed esercitazioni su come abbattere un repository SVN esistente in Git, ma nulla di come spingere un repository Git in un nuovo repository SVN. Mi aspetto che ci debba essere un modo per farlo con una combinazione di git-svn e un nuovo ramo, un rebasing e tutti quei termini meravigliosi, ma sono un principiante Git e non mi sento sicuro con nessuno di loro.

Quindi voglio solo eseguire un paio di comandi per inviare i commit a quel repository SVN quando scelgo. Vorrei continuare a usare Git e avere solo il repository SVN che rispecchia ciò che è in Git.

Sarò l'unica persona a impegnarsi in SVN, se questo fa la differenza.


1
Nota: probabilmente perderai i tuoi timbri originali quando lo fai. Le nuove date si baseranno sul tempo dell'importazione in Subversion.
nobar,

Per coloro che sono alla ricerca di informazioni più aggiornate, alcuni potrebbero trovare utile il seguente post durante la loro ricerca nell'automazione: deliciousbrains.com/deploying-wordpress-plugins-travis
Josh Habdas

Risposte:


403

Ne avevo bisogno anche io, e con l'aiuto della risposta di Bombe + un po 'di armeggi, l'ho fatto funzionare. Ecco la ricetta:

Importa 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

Dopo # 3 riceverai un messaggio criptico come questo:

Utilizzando un livello superiore di URL: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

Ignoralo e basta.

Quando corri # 5, potresti avere conflitti. Risolvili aggiungendo file con stato "non unito" e riprendendo rebase. Alla fine, avrai finito; quindi sincronizzare nuovamente il repository SVN, utilizzando dcommit. È tutto.

Mantenere i repository sincronizzati

Ora puoi sincronizzare da SVN a Git, usando i seguenti comandi:

git svn fetch
git rebase trunk

E per sincronizzare da Git a SVN, utilizzare:

git svn dcommit

Nota finale

Potresti provare questo su una copia locale, prima di fare domanda per un repository live. Puoi fare una copia del tuo repository Git in un posto temporaneo; utilizzare semplicemente cp -r, poiché tutti i dati si trovano nel repository stesso. È quindi possibile impostare un repository di test basato su file, utilizzando:

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

E controlla una copia funzionante, usando:

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

Ciò ti consentirà di giocare con le cose prima di apportare modifiche permanenti.

Addendum: se sbagli git svn init

Se si esegue accidentalmente git svn initcon l'URL errato e non si è abbastanza intelligenti da eseguire un backup del proprio lavoro (non chiedere ...), non è possibile eseguire nuovamente lo stesso comando. Puoi tuttavia annullare le modifiche emettendo:

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

E rimuovi la sezione [svn-remote "svn"]sezione.

È quindi possibile eseguire git svn initnuovamente.


2
Bella risposta. Questo rovina anche le date di commit?
Drew Noakes,

4
Buone domande - Sfortunatamente, non conosco neanche la risposta. Questa è più una guida pratica di ciò che ho scoperto funzionare. Non capisco completamente tutti i dettagli. Per quanto riguarda le date di commit, immagino che potresti fare un test e scoprirlo. Ricorda che puoi avviare un repository svn locale (basato su fs), per testare le cose.
troelskn,

10
Ho seguito questi stessi passaggi usando "git rebase --onto trunk --root" al posto del passaggio 5 e ho avuto molto più successo. Solo una manciata di conflitti di fusione da risolvere, anziché tonnellate.
Kubi,

5
Nel mio caso questa sequenza non ha funzionato. È stato sempre visualizzato un messaggio "Impossibile determinare le informazioni SVN a monte dalla cronologia HEAD". Quindi, nessun dcommit possibile.
Fedir RYKHTIK il

2
Non importa, ho cercato di diventare intelligente e di omettere -s poiché non volevo seguire la configurazione standard SVN (trunk / branch / tags /). Non è riuscito a farlo funzionare affatto senza quello.
James McMahon,

33

Ecco come l'abbiamo fatto funzionare:

Clona il tuo repository Git da qualche parte sul tuo computer.

Apri .git / config e aggiungi quanto segue (da Mantenimento di un mirror SVN di sola lettura di un repository Git ):

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

Ora, da una finestra della console, digitare questi:

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

Ora, se si interrompe qui per qualsiasi motivo, digita queste tre righe:

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

E infine, puoi impegnarti in SVN:

git svn dcommit

Nota: dopo scarto sempre quella cartella.


6
+1 questo in realtà ha funzionato per me (non ho tronco / base qualunque), in contrasto con altre risposte che continuavano a dareUnable to determine upstream SVN information from HEAD history.
stijn


2
Ho provato questa tecnica, ma non ha importato la storia. A proposito, "git merge master" ora è "git merge --allow-unrelated-histories master"
Berend de Boer,

1
Se vuoi assolutamente sovrascrivere cosa c'è in SVN con cosa c'è in git, usa git merge -s recursive -Xtheirs --allow-unrelated-histories master.
user1475814

28

L'uso git rebasediretto perderà il primo commit. Git lo tratta in modo diverso e non può modificarlo.

Esiste una procedura che conserverà la cronologia completa: http://kerneltrap.org/mailarchive/git/2008/10/26/3815034

Trascriverò la soluzione qui, ma i crediti sono per Björn.

Inizializza git-svn:

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

--Prefix ti dà rami di localizzazione remoti come "svn / trunk" che è bello perché non ottieni nomi ambigui se chiami il tuo ramo locale solo "trunk" allora. Ed -sè una scorciatoia per il layout standard trunk / tag / rami.

Prendi le cose iniziali da SVN:

git svn fetch

Ora cerca l'hash del tuo commit root (dovrebbe mostrare un singolo commit):

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

Quindi ottenere l'hash del commit del trunk vuoto:

git rev-parse svn/trunk

Crea l'innesto:

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

Ora, "gitk" dovrebbe apparire svn/trunkcome il primo commit su cui si basa il tuo ramo master.

Rendi permanente l'innesto:

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

Rilascia l'innesto:

rm .git/info/grafts

gitk dovrebbe ancora mostrarsi svn/trunknegli antenati del maestro.

Linearizza la tua cronologia sul tronco:

git svn rebase

E ora "git svn dcommit -n" dovrebbe dirti che si impegnerà su trunk.

git svn dcommit

Puoi spiegare in che modo questa tecnica è diversa da quella sopra più chiaramente.
cmcginty,

3
Quando provo "git rev-parse svn / trunk" riporta una revisione sconosciuta o un percorso che non si trova nell'albero di lavoro.
Adam Ness,

Questa è l'unica risposta che ha funzionato per me, tranne i passaggi git filter-branch e drop graft non erano necessari: ho fatto un rebase dopo aver creato l'innesto e poi git svn dcommit.
fc7,

8

Crea una nuova directory nel repository Subversion per il tuo progetto.

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

Passa al tuo progetto gestito da Git e inizializza git-svn.

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

Ciò creerà un unico commit perché la directory del progetto SVN è ancora vuota. Ora rifai tutto su quel commit git svn dcommite dovresti aver finito. Tuttavia, rovinerà seriamente le tue date di commit.


Ho usato questa risposta con le istruzioni su hassox.blogspot.com/2007/12/using-git-with-svn.html Ho seguito questi comandi, quindi "#git branch -a" per vedere il nome del trunk. Quindi: # git checkout -b local-svn trunk # git merge master # git svn dcommit Ricorda di .gitignore la directory .svn!
cflewis

Dato che ho appena eseguito la stessa operazione, volevo chiarire che da qualche tempo (gennaio '09), git può eseguire un'operazione di rebase sul commit root. Questo rende il processo molto più semplice di quanto indichino molti dei vecchi articoli, vedi commenti su its.arubything.com/2009/1/4/…
Louis Jacomet,

Che cosa fa l'opzione "-s" git svn init? Non riesco a vederlo nelle pagine man di git svn.
Nathan,

Leggi di nuovo la pagina man, forse cerca "-s" perché è lì dentro. È un alias per "--stdlayout".
Bombe,

7

Git -> SVN con cronologia di commit completa

Ho avuto un progetto Git e ho dovuto spostarlo in SVN. È così che l'ho fatto, mantenendo l'intera cronologia dei commit. L'unica cosa che si perde è l'ora di commit originale poiché libSVN imposterà l'ora locale quando lo facciamo git svn dcommit.

Come:

  1. Avere un repository SVN in cui vogliamo importare le nostre cose e clonarle con git-svn:

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. Vai lì:

    cd repo.git-svn
    
  3. Aggiungi il telecomando del repository Git (in questo esempio sto usando C: /Projects/repo.git ). Vuoi spingere su SVN e dargli il nome old-git:

    git remote add old-git file:///C/Projects/repo.git/
    
  4. Recupera le informazioni dal ramo master dal repository old-git al repository corrente:

    git fetch old-git master
    
  5. Effettua il checkout del ramo master del telecomando old-git in un nuovo ramo chiamato vecchio nel repository corrente:

    git checkout -b old old-git/master`
    
  6. Rebase per mettere HEAD sopra old-git / master. Ciò manterrà tutti i tuoi impegni. Ciò che sostanzialmente fa è portare tutto il tuo lavoro fatto in Git e metterlo in cima al lavoro a cui stai accedendo da SVN.

    git rebase master
    
  7. Ora torna al tuo ramo principale:

    git checkout master
    

    E puoi vedere che hai una cronologia di commit pulita. Questo è ciò che vuoi spingere in SVN.

  8. Spingi il tuo lavoro su SVN:

    git svn dcommit
    

È tutto. È molto pulito, senza hacking e tutto funziona alla perfezione. Godere.


Un processo simile è anche dettagliato su chani.wordpress.com/2012/01/25/…
TWiStErRob

Sembra. Tuttavia, trovo la sua strada piuttosto confusa e la mia è molto più breve (8 passaggi rispetto al 19/23). Forse non la capisco correttamente, ma penso che mescoli i comandi svn e git al suo secondo proiettile.
codingdave

Ah, sì, la differenza è che il tuo processo importa git nella radice del repository SVN, il suo lo importa in una sottocartella, ecco perché git svnsono necessari i pochi preparativi.
TWiStErRob

Nel passaggio 7, non dovrebbe esserci un git merge old? Per me sembra che tu stia facendo un dcommit di maestro che non sei cambiato ?!
Alexander,

@Alexander usando 'git rebase master' produciamo un'unione di avanzamento rapido, ovvero un'unione lineare senza un commit di unione con due genitori. Vogliamo avere una storia lineare qui.
codingdave,


3

Avevo bisogno di trasferire il mio repository Git esistente in un repository SVN vuoto.

Ecco come sono riuscito a fare questo:

$ 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

Ha funzionato senza problemi. Spero che questo aiuti qualcuno.

Dato che dovevo autorizzarmi con un nome utente diverso dal repository SVN (il mio originusa l'autenticazione con chiave pubblica / privata), ho dovuto usare la --usernameproprietà.


potrebbe essere necessario installare git-svnprima di questo è possibile, vedere stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive

2

Se vuoi continuare a lavorare con Git come repository principale e devi solo "esportare" le revisioni in SVN di volta in volta, puoi usare Tailor per mantenere sincronizzato il repository SVN. Può copiare le revisioni tra diversi sistemi di controllo del codice sorgente e aggiornerebbe SVN con le modifiche apportate in Git.

Non ho provato una conversione da Git a SVN, ma per un esempio SVN -> SVN vedi questa risposta .


2

Ancora un'altra sequenza che ha funzionato (con alcuni commenti su ogni passaggio):

  1. Installa git-svne subversiontoolkit:

    sudo apt-get install git-svn subversion
    
  2. Passa all'interno di PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. Crea il percorso del progetto sul server Subversion (sfortunatamente il git-svnplugin corrente ha un difetto rispetto a TortoiseSVN). Non è possibile memorizzare il codice sorgente direttamente nel file PROJECT_FOLDER. Invece, per impostazione predefinita, caricherà tutto il codice in PROJECT_FOLDER/trunk.

    svn mkdir --prents protocol: /// path / to / repo / PROJECT_FOLDER / trunk -m "creazione di segnaposto git repo"

Questo è il luogo dove trunkalla fine del percorso è obbligatorio

  1. Inizializza il git-svncontesto del plugin all'interno della .gitcartella

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

    Questo è il luogo dove trunkalla fine del percorso non è necessario

  2. Recupera Subversioninformazioni vuote su un repository

    git svn fetch
    

    Questo passaggio aiuta a sincronizzare il server Subversion con il git-svnplugin. Questo è il momento in cui il git-svnplugin stabilisce il remotes/originpercorso e lo associa alla trunksottocartella sul lato server.

  3. Sostituisci i vecchi commit di Git avvenuti prima che il git-svnplugin fosse coinvolto nel processo (questo passaggio è facoltativo )

    git rebase origin/trunk
    
  4. Aggiungi file nuovi / modificati da confermare (questo passaggio è regolare per le attività di Git ed è facoltativo )

    git add .
    
  5. Salva i file appena aggiunti nel repository Git locale (questo passaggio è facoltativo ed è applicabile solo se è stato utilizzato il passaggio 7):

    git commit -m "Importing Git repository"
    
  6. Inserendo tutta la cronologia delle modifiche del progetto nel server Subversion:

    git svn dcommit
    

1

È possibile creare un nuovo repository SVN. Esporta il tuo progetto Git (completando i file .git). Aggiungilo al repository SVN (inizializzando il repository con quello che avevi finora in Git). Quindi utilizzare le istruzioni per l'importazione di repository SVN in un nuovo progetto Git.

Ma questo perderà la tua storia Git precedente.



1

Vorrei condividere un ottimo strumento utilizzato nella comunità di WordPress chiamato Scatter

Git plugin WordPress e un po 'di sanità mentale

Ciò consente agli utenti di inviare automaticamente il proprio repository Git a wordpress.org SVN. In teoria, questo codice può essere applicato a qualsiasi repository SVN.


Il collegamento sembra essere effettivamente interrotto ( "Il server su evansolomon.me sta impiegando troppo tempo a rispondere." ).
Peter Mortensen,

1

Di recente ho dovuto migrare diversi repository Git su SVN e, dopo aver provato tutte le soluzioni che ho trovato, quello che alla fine ha funzionato per me è stato Mercurial (sì, usando un terzo VCS). Usando questa guida , ho ideato il seguente processo (su Linux, ma l'idea di base dovrebbe funzionare anche su Windows).

  1. I pacchetti necessari:

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. Mercurial deve essere configurato aggiungendo quanto segue a ~/.hgrc:

    [extensions]
    hgext.convert=
    
  3. Creare alcune directory di lavoro temporanee (avevo diversi repository da migrare, quindi ho creato directory per le versioni SVN e Git, per tenerle separate):

    $ mkdir svn
    $ mkdir git
    
  4. Crea un repository SVN locale vuoto:

    $ svnadmin create svn/project
    
  5. Clona il repository Git esistente:

    $ git clone server/path/project.git git/project
    
  6. Lascia che Mercurial faccia la sua cosa:

    $ hg convert --dest-type svn git/project svn/project
    
  7. Ora il repository SVN dovrebbe contenere la cronologia completa del commit, ma non con i timestamp originali. Se questo non è un problema, passare alla parte successiva al passaggio 11.

  8. Con un po 'di lavoro, è possibile modificare la data e l'ora di ciascun commit . Dato che i miei repository sono abbastanza piccoli, è stato possibile per me farlo manualmente. Innanzitutto, creare un pre-revprop-changehook nel repository SVN con i seguenti contenuti, per consentire la modifica della proprietà necessaria:

    #!/bin/bash
    exit 0;
    

    Questo script deve essere reso eseguibile:

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial ha creato una copia funzionante del repository SVN, denominato project -wc, quindi passa ad esso e modifica i tempi di commit:

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

    Inserire la data e l'ora corrette (prestare attenzione ai fusi orari!) E salvare. Dovresti ricevere un messaggio che dice "Imposta nuovo valore per la proprietà svn: data sulla revisione 1".
    Ora risciacqua e ripeti per ogni altra revisione.

  10. Opzionalmente controlla la cronologia di commit per assicurarti che tutto appaia OK:

    $ svn log -r 1:HEAD
    

    Quindi tornare indietro di un livello:

    $ cd ..
    
  11. Dump del repository:

    $ svnadmin dump svn/project > project.dump
    
  12. E carica il dump sul tuo server Subversion. Fatto!

Questo processo probabilmente funzionerebbe anche direttamente tra i repository remoti, ma ho trovato più facile lavorare con quelli locali. Risolvere i tempi di commit è stato molto impegnativo, ma nel complesso il processo è stato molto più semplice di qualsiasi altro metodo che ho trovato.


1

ci sono tre metodi :

  1. rebase : come le altre risposte

  2. commit id: trova prima svn commit id e git prima commit id, echo loro in .git / info / innesti: echo "git_id svn_id}" > .git/info/graftspoigit svn dcommit

  3. controlla ogni commit git, copia i file in svn_repo, svn commit

bash demo : demo demo github

v1.x : usa rebase e commit id

v2.x: usa i file di copia, quindi svn commit


0

Nel mio caso, ho dovuto avviare un progetto pulito da SVN

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

aggiungi tutte le fonti del tuo progetto ...

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

0

Voglio solo condividere parte della mia esperienza con la risposta accettata. Ho fatto tutti i passaggi e tutto andava bene prima di eseguire l'ultimo passaggio:

git svn dcommit

$ git svn dcommit

Uso del valore non inizializzato $ u in sostituzione (s ///) in /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm riga 101.

Uso del valore non inizializzato $ u in concatenazione (.) O stringa in /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm riga 101. refs / remotes / origin / HEAD: ' https://192.168.2.101/ svn / PROJECT_NAME 'non trovato in' '

Ho trovato il thread https://github.com/nirvdrum/svn2git/issues/50 e infine la soluzione che ho applicato nel seguente file nella riga 101 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm

Ho sostituito

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

con

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

Questo risolto il mio problema.


-1

Cosa succede se non si desidera eseguire il commit di tutti i commit eseguiti in Git nel repository SVN? Cosa succede se si desidera solo inviare in modo selettivo commit sulla pipe? Bene, ho una soluzione migliore.

Conservo un repository Git locale in cui tutto ciò che faccio è recuperare e unire da SVN. In questo modo posso assicurarmi di includere tutte le stesse modifiche di SVN, ma mantengo la mia cronologia di commit completamente separata da SVN.

Quindi tengo una copia di lavoro locale SVN separata che si trova in una cartella separata. È quello da cui eseguo il commit su SVN e per questo uso semplicemente l'utilità della riga di comando SVN.

Quando sono pronto a trasferire lo stato del mio repository Git locale su SVN, copio semplicemente l'intero disordine di file nella copia di lavoro SVN locale e lo commetto da lì usando SVN anziché Git.

In questo modo non devo mai fare alcun rebasing, perché il rebasing è come il freebasing.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.