Soluzione semplice: rimuovere il ramo "lavoro" dopo l'unione
Risposta breve: puoi usare git come preferisci (vedi sotto per un semplice flusso di lavoro), inclusa l'unione. Assicurati solo di seguire ogni ' git merge work ' con ' git branch -d work ' per eliminare il ramo di lavoro temporaneo.
Spiegazione di fondo:
il problema di unione / dcommit è che ogni volta che 'git svn dcommit' un ramo, la cronologia di unione di quel ramo è 'appiattita': git dimentica tutte le operazioni di unione che sono entrate in questo ramo: viene conservato solo il contenuto del file, ma il fatto che questo contenuto (parzialmente) provenga da un altro ramo specifico è perso. Vedi: Perché git svn dcommit perde la cronologia degli commit di fusione per le filiali locali?
(Nota: non c'è molto che git-svn possa fare al riguardo: svn semplicemente non capisce le fusioni git molto più potenti. Quindi, all'interno del repository svn queste informazioni di unione non possono essere rappresentate in alcun modo.)
Ma questo è l' intero problema. Se elimini il ramo 'lavoro' dopo che è stato unito al 'ramo principale', il tuo repository git è pulito al 100% e assomiglia esattamente al tuo repository svn.
Il mio flusso di lavoro:
ovviamente, per prima cosa ho clonato il repository svn remoto in un repository git locale (questo potrebbe richiedere del tempo):
$> git svn clone <svn-repository-url> <local-directory>
Quindi tutto il lavoro avviene all'interno della "directory locale". Ogni volta che devo ottenere aggiornamenti dal server (come 'svn update'), faccio:
$> git checkout master
$> git svn rebase
Faccio tutto il mio lavoro di sviluppo in un 'lavoro' di ramo separato creato in questo modo:
$> git checkout -b work
Naturalmente, puoi creare tutti i rami per il tuo lavoro che desideri e unirli e riformularli tra loro come preferisci (eliminali quando hai finito con loro --- come discusso di seguito). Nel mio lavoro normale, mi impegno molto frequentemente:
$> git commit -am '-- finished a little piece of work'
Il prossimo passo (git rebase -i) è facoltativo --- sta semplicemente ripulendo la storia prima di archiviarla su svn: Una volta raggiunta una pietra miliare stabile che voglio condividere con gli altri, riscrivo la storia di questo 'lavoro' diramare e ripulire i messaggi di commit (gli altri sviluppatori non hanno bisogno di vedere tutti i piccoli passi ed errori che ho fatto lungo la strada --- solo il risultato). Per questo, lo faccio
$> git log
e copia l'hash sha-1 dell'ultimo commit attivo nel repository svn (come indicato da un git-svn-id). Quindi chiamo
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
Basta incollare l'hash sha-1 del nostro ultimo svn commit anziché il mio. Potresti voler leggere la documentazione con 'git help rebase' per i dettagli. In breve: questo comando prima apre un editor che presenta i tuoi commit ---- cambia 'pick' in 'squash' per tutti quei commit che vuoi schiacciare con i commit precedenti. Naturalmente, la prima riga dovrebbe rimanere come un 'pick'. In questo modo, puoi condensare i tuoi molti piccoli impegni in una o più unità significative. Salva ed esci dall'editor. Riceverai un altro editor che ti chiederà di riscrivere i messaggi del registro di commit.
In breve: dopo aver finito 'l'hacking del codice', massaggio il mio ramo 'lavoro' fino a quando non appare come voglio presentarlo agli altri programmatori (o come voglio vedere il lavoro tra qualche settimana quando sfoglio la cronologia) .
Per inviare le modifiche al repository svn, faccio:
$> git checkout master
$> git svn rebase
Ora siamo di nuovo al vecchio ramo 'master' aggiornato con tutte le modifiche avvenute nel frattempo nel repository svn (le tue nuove modifiche sono nascoste nel ramo 'work').
Se ci sono cambiamenti che potrebbero scontrarsi con i tuoi nuovi cambiamenti di "lavoro", devi risolverli localmente prima di poter spingere il tuo nuovo lavoro (vedi i dettagli più avanti). Quindi, possiamo inviare le nostre modifiche a svn:
$> git checkout master
$> git merge work # (1) merge your 'work' into 'master'
$> git branch -d work # (2) remove the work branch immediately after merging
$> git svn dcommit # (3) push your changes to the svn repository
Nota 1: Il comando 'git branch -d work' è abbastanza sicuro: ti permette solo di eliminare i rami che non ti servono più (perché sono già uniti nel tuo ramo attuale). Se si esegue questo comando per errore prima di unire il proprio lavoro al ramo "master", viene visualizzato un messaggio di errore.
Nota 2: assicurati di eliminare il tuo ramo con 'git branch -d work' tra fusione e dcommit: se provi a cancellare il ramo dopo dcommit, ricevi un messaggio di errore: Quando fai 'git svn dcommit', git dimentica che la tua filiale è stata unita a "master". Devi rimuoverlo con 'git branch -D work' che non fa il controllo di sicurezza.
Ora creo immediatamente un nuovo ramo "lavoro" per evitare l'hacking accidentale sul ramo "principale":
$> git checkout -b work
$> git branch # show my branches:
master
* work
Integrazione del tuo "lavoro" con le modifiche su svn:
Ecco cosa faccio quando "git svn rebase" rivela che altri hanno cambiato il repository svn mentre stavo lavorando sul mio ramo "lavoro":
$> git checkout master
$> git svn rebase # 'svn pull' changes
$> git checkout work # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master # try again to push my changes
$> git svn rebase # hopefully no further changes to merge
$> git merge integration # (1) merge your work with theirs
$> git branch -d work # (2) remove branches that are merged
$> git branch -d integration # (2) remove branches that are merged
$> git svn dcommit # (3) push your changes to the svn repository
Esistono soluzioni più potenti:
il flusso di lavoro presentato è semplicistico: usa i poteri di git solo all'interno di ogni round di 'update / hack / dcommit' --- ma lascia la storia del progetto a lungo termine altrettanto lineare come il repository svn. Questo va bene se vuoi solo iniziare a usare git merges in piccoli primi passi in un progetto svn legacy.
Quando acquisisci maggiore familiarità con l'unione di git, non esitare a esplorare altri flussi di lavoro: se sai cosa stai facendo, puoi mescolare le fusioni di git con le fusioni di svn ( Usando git-svn (o simili) solo per dare una mano con svn merge? )