2010-05-31 12 views
26

Nel mio progetto stanno emergendo alcune sovversioni complesse: grandi rami separati da molto tempo. Svn dà troppi conflitti - e alcuni sembrano spuri.Usare git-svn (o simile) * solo * per dare una mano con una svn unione?


Dato che git è lodato per un'esperienza di unione superiour, sarebbe nulla di buono da usare git-svnsolo per il vantaggio di rendere l'unione più gestibile?


può Consiglieresti altre alternative (ad es. svk, hgsvn) per diminuire il dolore unione?

Alcuni conflitti sono abbastanza facili da risolvere (ad es. Java imports, whitespace), quindi mi chiedo anche se ci siano soluzioni automatizzate per questi.

Un passaggio completo a DVCS potrebbe avvenire in futuro (alcuni di noi vorrebbero che), ma non ora. (AGGIORNAMENTO: questo non è più vero - il team è passato completamente di recente e ne è felice).

Grazie in anticipo.

PS: ci sono post che sembrano essere correlati (ad esempio git-svn merge 2 svn branches) ma non rispondono completamente a questa domanda.

Aggiornamento: vedere la mia risposta -novice- dopo essere scesa (e su :) questa strada.

+0

Perché non * solo * utilizzando git-svn per tutto? –

+0

@ Vi.questa è una domanda separata di primo livello - potresti aggiungerla come segue: -/Il mio era approssimativamente: "introduresti git-svn in un team basato su SVN, solo per dare una mano con un grande fusione? " – inger

+1

Dopo aver unito * solo * potrebbero pensare di iniziare * solo * utilizzandolo ... –

risposta

33

Cercando di rispondere alla mia domanda: l'uso di git per svn merges sembra promettente.

Aggiornamento: non è solo promettente, è un grande successo. In breve, Linus was right.

Ha appena completato un'enorme fusione di 2 rami svn separati da 1,5 anni; File 3k sono stati cambiati, ha ottenuto tonnellate di conflitti in svn (~ 800 penso).

ho trovato git & git-svn un risparmiatore di vita:

  • risoluzione automatica dei conflitti: per cominciare, ha dato un sacco di file di meno in conflitto (~ metà credo)
  • prestazioni incredibili
  • eccellente repo/branching model, flussi di lavoro flessibili: facile sperimentazione con vari approcci, come il chunk-by-chunk (in tempo) si fondono, eseguendo sempre controlli di integrità (compilazione, ecc.); ogni volta che si verificano problemi: basta tornare indietro. Puoi sempre fare un passo indietro quando necessario.
  • usabilità, grandi attrezzature:
    • git-log (e le sottostanti git-rev-parse opzioni), nulla può essere più potente di questo. È anche utile: -p ti dà le differenze in un colpo solo; in svn si ottiene un registro, quindi si trova il diff per quel "revision-1: revision", o si usano le UI goffe. Trova quando una stringa è stata aggiunta/rimossa nel repository, ricerca simultaneamente su più diramazioni
    • gitk: estremamente utile per la visualizzazione di storie di filiali, combinate con ottime capacità di ricerca. Non ho visto nulla di simile in altri strumenti, specialmente non così veloce come questo.Nevermind è in Tk, è semplicemente eccezionale
    • git gui: funziona bene, anche se non il più sexy - grande aiuto per i principianti di scoprire cose
    • blame: un miracolo. Sì, rileva dove il segmento originale viene da (copia & incolla ecc)
    • mergetool: molta esperienza più piacevole che dando il via alla grande svn merge che poi si ferma ogni volta (. Cioè ogni 5 minuti) si corre in un conflitto, premere ' (p) ostpone ', che cercare manualmente i file in conflitto successivamente. Preferito un sapore di questo integrato in git gui (necessario uno tiny patch per quello). Trovato integrazione di strumenti di diffusione esterni meglio configurabili rispetto a svn.
    • pluggable fondono driver e controllo a grana fine di loro
    • rebase consentito di filtrare le parti Messier della storia svn
  • distribuzione: non c'è bisogno di venire in ufficio quando si lavora su questo, potrebbe mettere in pausa & progresso step-by-step su treno/aereo, ecc ..
    • un drive USB con Unison fatta la sincronizzazione di lavoro < -> a casa un pezzo di torta
    • questo non sarebbe h ave stato possibile senza la compressione folle di git (5 anni di progetto con 26k impegna, tonnellate di rami e file binari, tronco svn checkout: 1.9GB => tutti questi in repo piena git:! 1.4GB)

Quindi, questo può davvero fare la differenza da un incubo alla gioia - specialmente se ti piace imparare (cosa che richiede un certo sforzo in questo caso - immagino come imparare una moto dopo una bicicletta).

Anche se non posso costringere tutti in azienda a passare immediatamente - non intendevo davvero farlo. Anche in questo caso, git-svn ci salva da 'immergendo la punta prima' approccio .. Ma vedendo le reazioni dei colleghi l'interruttore potrebbe accadere molto prima che qualcuno aspettava :)

avrei dire- anche se ci dimentichiamo fonde & commit, questa roba è già grande come un frontend di sola lettura per le query, la visualizzazione, backup, ecc ..

Caveat:

"non dcommit Git merge impegna a repository Subversion Subversion non gestisce. si fonde allo stesso modo come Git, e questo causerà problemi. Questo significa che si dovrebbe tenere il Git sviluppo storia lineare (cioè non la fusione da altri rami, proprio rebasing)." (ultimo comma http://learn.github.com/p/git-svn.html)

Un'altra fonte eccellente è la sezione Pro Git book ' Il cambio di rami attivi dice sostanzialmente che l'unione funziona, ma dcommit memorizzerà solo il contenuto dell'unione, ma la cronologia verrà compromessa (che interrompe le successive fusioni), quindi è necessario rilasciare il ramo di lavoro dopo l'unione. senso dopo tutto, e in pratica è facile evitare trappole qui ..in Svn, ho trovato che le persone di solito non si riuniscono di nuovo, quindi questo potrebbe essere visto come un passo indietro se vieni da Git World in primo luogo.

In ogni caso, il dcommit ha funzionato per me. L'ho fatto sul mio svn workbranch che ho tenuto solo per questo, quindi ho evitato qualsiasi conflitto extra in quel momento. Tuttavia, ho deciso di eseguire l'unione finale da questo workbranch al tronco svn in svn (dopo aver sincronizzato tutto in git); --ignore-ancestry ha dato i migliori risultati lì.

Aggiornamento: come ho scoperto in seguito, gli ultimi passaggi sopra (ramo svn extra e unione - ignora-ascendenza) sono facilmente evitati semplicemente mantenendo lineare il ramo da cui si sta inviando. Come dice Gabe in basso, merge --squash crea semplicemente un semplice commit stupido svn-friendly. Proprio quando pronto con enorme merge (s) sul mio ramo locale (che potrebbe richiedere giorni/settimane), vorrei ora solo:

git checkout -b dcommit_helper_for_svnbranch svnbranch 
git merge --squash huge_merge_work_with_messy_nonlinear_history 
git commit 'nice merge summary' # single parent, straight from the fresh svnbranch 
git dcommit 

so che il monitoraggio fusione non sarà grande lavoro dal svn-side , finché non passiamo completamente. Non posso aspettare per quello.


UPDATE: @ Kevin ha chiesto qualche dettaglio in più su tutto il processo di fusione rami SVN .. Ci sono tantissime articoli, messaggi là fuori, ma come un principiante ho trovato alcuni dei confusione/fuorvianti/out di data .. in ogni caso, il modo in cui lo faccio in questi giorni (ovviamente, bloccati con git-svn dopo quella storia si fondono, così come alcuni colleghi infettati) ..

git svn clone -s http://svn/path/to/just-above-trunk # the slowest part, but needed only once ever..you can every single branch from the svn repo since revision #1. 2) 
git svn fetch   # later, anytime: keep it up to date, talking to svn server to grab new revisions. Again: all branches - and yet it's usually a faster for me than a simple 'svn up' on the trunk:)  
# Take a look, sniff around - some optional but handy commands: 
git gui & # I usually keep this running, press F5 to refresh 
gitk --all  # graph showing all branches 
gitk my-svn-target-branch svn-branch-to-merge # look at only the branches in question 
git checkout -b my-merge-fun my-svn-target-branch # this creates a local branch based on the svn one and switches to it..before you notice :) 
# Some handy config, giving more context for conflicts 
git config merge.conflictstyle diff3 
# The actual merge.. 
git merge svn-branch-to-merge # the normal case, with managable amount of conflicts 
# For the monster merge, this was actually a loop for me: due to the sheer size, I split up the 2 year period into reasonable chunks, eg. ~1 months, tagged those versions ma1..ma25 and mb1..mb25 on each branch using gitk, and then repeated these for all of them 
git merge ma1 # through ma25 
git merge mb1 # through mb25 
# When running into conflicts, just resolve them.. low tech way: keep the wanted parts, then "git add file" but you can 
git mergetool # loops through each conflicted file, open your GUI mergetool of choice..when successful, add the file automatically. 
git mergetool my-interesting-path # limit scope to that path 

in realtà ho preferito usare 'git integrazione incorporata di mergetool di gui (clic destro su file in conflitto). Comunque è un po 'limitato, quindi vedi la mia piccola patch qui sopra, che ti permette di collegare uno script di shell in cui puoi invocare qualsiasi mergetools che preferisci (ne ho provati a volte in parallelo perché causavano una quantità sorprendente di dolore .. ma normalmente mi sono bloccato con kdiff3 ..

Quando un passo di fusione va bene (nessun conflitto), una fusione commit avviene automaticamente, in caso contrario, di risolvere i conflitti allora

git commit # am usually doing this in the git gui as well.. again, lightning fast. 

l'ultima fase .. si noti che finora avevamo solo commit locali, non parlando ancora con il server svn. A meno che tu non abbia usato --squash o altri trucchi, ora finisci con un grafico in cui il tuo commit di unione ha 2 genitori: i suggerimenti del tuo sv rami n-mirror. Ora questo è il solito trucco: svn può solo prendere la cronologia lineare ... quindi 'git-svn' lo semplifica semplicemente lasciando cadere il secondo genitore (svn-branch-to-merge nel caso precedente) .. quindi il vero tracciamento di unione è andato sul lato svn..ma altrimenti in questo caso va bene.

Se si desidera un modo più sicuro/pulito, è qui che entra in gioco il frammento precedente: esegui l'unione finale con --squash. Adattato il precedente a questo flusso:

git checkout -b dcommit_helper_for_svnbranch my-svn-target-branch # another local workbranch.. basically needed as svn branches (as any other remote branch) are read-only 
git merge --squash my-merge-fun 
git commit 'nice merge summary' # single parent, straight from the fresh svn branch 
git dcommit # this will result in a 'svn commit' on the my-svn-target-branch 

oops, questo sta diventando troppo lungo, fermandosi prima troppo tardi .. Buona fortuna.

+2

+1 per la tua recensione completa e auto-risposta –

+0

grazie. Spero che aiuti anche gli altri. – inger

+0

Ciao Inger, fantastico che tu possa far funzionare tutto questo! Sono un principiante e sto valutando git proprio per questo caso d'uso - unendo due rami che hanno molti file e molti falsi conflitti SVN. Riesci a mettere insieme un breve elenco di codici su come impostare il repository e svolgere il lavoro? Per esempio. git svn clone myrep; git checkout -b branchA; git checkout -b branchB; git merge branchA branchB; git commit, git svn dcommit, ecc.? Voglio assicurarmi di capire completamente il tuo approccio prima di avviarlo perché git svn clone richiede giorni :-(Grazie in anticipo. –

3

Ho appena lavorato su questo da solo. Un simpler method passa l'opzione --squash--squash, che eseguirà l'unione senza registrare un commit di unione, mantenendo lineare la cronologia in modo da non confondere git-svn.

La mia unione era anche molto grande e ho dovuto impostare git config diff.renamelimit 0 in modo che git potesse trovare correttamente tutti i nomi.

+1

Cheers per quello. Sì, ho usato anche --squash merge. È anche utile quando vuoi un singolo commit combinato piuttosto che molti piccoli (come alternativa a 'rebase -i'). – inger

+0

L'opzione di unione '--no-ff' sembra essere stata creata per questo:' git merge --no-ff mybranch' –

3

Sono disponibili nuovi strumenti che risolvono molti problemi di git-svn e offrono un'esperienza molto migliore per l'uso di Subversion e Git.

Tra le altre cose questi strumenti risolvono alcuni problemi di ramificazione e unione. Ecco una panoramica:

  1. git-svn

    Dalla documentazione:

    CAVEATS

    ...

    esecuzione merge git o git pull NON è raccomandato su una filiale di cui intendi rinunciare. Subversion non rappresenta fusioni in alcun modo ragionevole o utile; quindi gli utenti che usano Subversion non possono vedere alcuna fusione che hai fatto. Inoltre, se si uniscono o si estraggono da un ramo git che è un mirror di un ramo SVN, dcommit potrebbe commettere il ramo sbagliato.

    Ci sono principalmente tre motivi per non dcommit merge impegna:

    • git-svn non invia automaticamente svn: mergeinfo immobili per rami uniti. Come risultato, Subversion non è in grado di tracciare le unioni eseguite da git. Ciò include normali fusioni e selezioni Git.

    • come git-svn non converte svn: ignora, svn: stile eol e altre proprietà SVN automaticamente, il commit unione non ha metadati corrispondenti in Git. Come risultato, dcommit non invia queste proprietà al repository SVN, quindi si perdono.

    • dcommit invia sempre le modifiche al ramo a cui fa riferimento un primo genitore di un commit di unione. A volte le modifiche appaiono dove l'utente non se lo aspetta.

  2. SubGit

    SubGit è un Git-SVN bidirezionale specchietto sul lato server.

    Se si ha accesso locale al repository Subversion, si può installare SubGit in esso:

    $ subgit configure $SVN_REPOS 
    # Adjust $SVN_REPOS/conf/subgit.conf to specify your branches and tags 
    # Adjust $SVN_REPOS/conf/authors.txt to specify git & svn authors mapping 
    $ subgit install $SVN_REPOS 
    ... 
    $ INSTALLATION SUCCESSFUL 
    

    In questo momento SubGit converte repository Subversion in Git (funziona nella direzione opposta oltre) e monta SVN e Git ganci. Come risultato, i repository Subversion e Git sono sincronizzati: ogni commit e push avvia hook che convertono immediatamente le modifiche in arrivo.

    SubGit converte svn: ignora le proprietà nei file .gitignore, svn: eol-style e svn: mime-type in .gitattributes, quindi i merge commit in Git mantengono questi metadati.

    Quando si esegue il merge merge, SubGit converte tutti i nuovi commit in revisioni di Subversion. Onora svn: proprietà mergeinfo, quindi l'operazione di unione viene correttamente seguita da SVN in seguito.

    Anche se l'utente invia una cronologia Git molto complessa, SubGit converte tutti i commit mantenendo validi i dati di tracciamento di unione. Una volta abbiamo spinto l'intera storia del git.git repository in una volta ed è stato correttamente convertito in SVN.

    SubGit è un prodotto commerciale. È gratuito per progetti open-source e accademici e anche per progetti con un massimo di 10 utenti.

    Per ulteriori dettagli, fare riferimento alla pagina di confronto SubGit documentation e git-svn.

  3. SmartGit

    SmartGit è un'alternativa lato client per git-svn.

    SmartGit supporta anche svn: ignore, svn: eol-style e svn: conversione delle proprietà di tipo mime. E imposta anche la proprietà svn: mergeinfo per i commit di unione. Aggiorna anche i dati di tracciamento necessari per i commit di cherry-pick.

    SmartGit è un client commerciale Git e Mercurial. È gratuito per uso non commerciale.

Divulgazione completa: sono uno degli sviluppatori di SubGit.

+0

Grazie, ho sentito parlare di SubGit prima. Sembra un approccio potente, tuttavia sembra più mirato a una conversione completa. La domanda sopra era più di un esperimento dip-a-toe, facendo un singolo svn merge senza accesso al server e chiunque ne avesse notato la società .. Comunque, nel frattempo ho gestito il team con git pieno, e anche con altre persone, e i ragazzi IT stanno pianificando una migrazione completa per la quale la doppia modalità potrebbe essere utile. Quindi, grazie per il tip.BTW è mergeinfo affidabile con tutte le versioni di Svn? – inger

+0

Ora stiamo lavorando su SubGit 2.0 che supporta la sincronizzazione bidirezionale dei repository Git e SVN situati su host diversi. Fondamentalmente, è possibile creare repository Git ovunque, specificare l'URL del repository SVN e abilitare la sincronizzazione SubGit per questi repository. Il sovraccarico è leggermente più ritardato sul lato Git senza alcun ritardo sul lato SVN. – vadishev

+0

Per quanto riguarda svn: mergeinfo, SVN supporta questa proprietà dalla versione 1.5, vale a dire più di 4 anni già. Prima che SVN non tenesse traccia della cronologia di unione. Per SVN 1.8 progettano di introdurre una funzione di fusione "simmetrica" ​​che dovrebbe migliorare il tracciamento della fusione. Si spera che ciò metta SVN alla pari con Git/Hg/etc a questo riguardo. – vadishev

Problemi correlati