2012-05-25 10 views
17

Ho cercato di avvolgere i modelli di ramificazione git. Ho guardato lo http://nvie.com/posts/a-successful-git-branching-model/ per alcune idee e provenendo da Subversion, una cosa che non vedevo l'ora di fare un cambiamento in un singolo posto e unirlo a tutte le filiali che lo richiedevano. In Subversion, abbiamo finito per fare molta copia del codice in giro.Git che unisce la correzione a più rami

Tuttavia, ancora non lo capisco completamente. Ecco un tipo di flusso di lavoro standard che ho e conterrà sempre conflitti.

# create new version branch 
git checkout master 
git checkout -b v3 
vim pom.xml # change branch version to "3.1-SNAPSHOT" 
git commit -a 
git checkout master 
vim pom.xml # change master version to "4.0-SNAPSHOT" 
git commit -a 

Così il maestro è a 4.0-SNAPSHOT e il ramo è a 3.1-SNAPSHOT.

Non voglio creare una correzione sul ramo e spostarlo nel bagagliaio.

git checkout v3 
git checkout -b hotfix 
vim file.txt # make a bugfix change 
git commit -a 
git checkout v3 
git merge hotfix # this works fine 
git checkout master 
git merge hotfix # this has a conflict since both branches have changed the version 

Capisco perché è successo e ha senso. C'è un modo migliore per farlo?

ho letto su cherry-pick, che ho provato e funziona:

git checkout v3 
git cherry-pick a518b0b75eaf28868 
git checkout master 
git cherry-pick a518b0b75eaf28868 

Tuttavia, che non sembra come il modo "corretto" per gestire questa situazione. Eventuali suggerimenti?

risposta

11

Davvero, il tuo la risposta dipende se vuoi che i tuoi alberi si basino sulla stessa storia ... Ad esempio, 4.0 è basato sull'ultimo 3.x + tutte le modifiche in 4.0 ...

Personalmente, io don ' Lo consiglio una volta che decidi di iniziare una nuova filiale (s) per una nuova versione (s). Ad un certo punto del tempo, il software sta prendendo una direzione diversa, quindi anche i tuoi rami dovrebbero.

Questo lascia git cherry-pick come soluzione ideale. Apportare la modifica a qualsiasi ramo abbia più senso, quindi selezionarlo nelle versioni precedenti. È lo stesso che se avessi estratto il vecchio ramo e manualmente applicato la stessa modifica, e fatto un nuovo commit. Lo mantiene pulito e al punto.

Git unire o rebase stanno per cercare di integrare la storia rami insieme, ognuno a suo modo, che ho il sospetto che non vuoi, quando il backport correzioni di bug, ecc ...

+0

Concordo (anche se penso che la risposta di @ ellotheth possa essere più elegante a seconda delle circostanze). Secondo git's [branching philosophy] (http://gitster.livejournal.com/42247.html) tu davvero sono dicendo che questo commit è l'unica cosa che appartiene a tutti i rami. Quindi la raccolta delle ciliegie è ciò che "dice" quello. –

+0

Grazie, penso che abbia senso. Venendo da Subversion, e quanto a volte fosse doloroso per noi spingere le correzioni al tronco e ai rami (fondamentalmente facendo la correzione due volte), avevo pensato nella mia mente che potevo semplicemente unire rami di funzionalità ovunque io volessi. Quando non funzionava come mi aspettavo, ero piuttosto stanco. "cherry-pick" ha un sacco di senso però. Ho solo bisogno di elaborare un processo che sia facile da comprendere per tutti gli sviluppatori e penso che ciò possa essere reso abbastanza chiaro. –

1

Nel caso, si sta lavorando sul ramo "4.0" e devono fare una correzione su "3.1", è possibile rebase "4.0" dopo che si impegnano "3.1":

git checkout 4.0 # you are on the feature brnach 4.0 
git stash # save current work so you can check out other branch 
git checkout 3.1  
git commit -a -m "bug fix" # do editing and commit 
git checkout "4.0" 
git stash apply # get back your changes 
git rebase "3.1" # change 4.1 so it branches of the current head of "3.1" 
+3

Mi piacerebbe commentare che mentre questo è possibile, rimuove la possibilità di fare affidamento sui tag, spingendo o condividendo in modo efficiente il codice 4.0. Rebase è grandioso, personalmente, ma non così grande quando hai già spinto. – gahooa

18

se si voleva ottenere super-tecnico a questo proposito, è possibile creare l'aggiornamento rapido da un antenato comune:

git merge-base v3 master 
git checkout -b hotfix <whatever you got from merge-base> 
# make your fix 
git checkout v3 && git merge --no-ff hotfix 
git checkout master && git merge --no-ff hotfix 

     v3--------v3 (hotfixed) 
    /  /
ancestor----hotfix 
     \   \ 
     master----master (hotfixed) 

la bandiera --no-ff mantiene l'etichetta hotfix ramo sulla punta aggiornamento rapido, invece di tirare l'etichetta v3 o master.

Personalmente, penso che sia eccessivo. Vorrei andare con gahooa: rendere l'aggiornamento rapido sul ramo che ha senso, quindi fondere o selezionare in base a come si desidera che i rami si correlano tra loro.

+3

+1 per 'merge-base',' --no-ff' e tutti i buoni consigli. 'cherry-pick' crea un nuovo commit: stessa diff, log message, timestamp, ma hash diversi. Se la storia chiara è importante, non penso che la merge sia un eccesso. Il cherry picking funzionerà per casi semplici, ma fai attenzione a cose come questa: http://news.ycombinator.com/item?id=3947950 –

+0

Ho imparato molto dalla tua risposta, grazie! –

0

Sono stato alle prese con questa domanda, e penso che se siete disposti a cambiare la vostra strategia di versioning un po '(cioè., allontanati dalle versioni -SNAPSHOT incoraggiate da Maven), questo potrebbe essere risolto usando una versione fissa (come SNAPSHOT o 0.0.0-SNAPSHOT) sul master (o qualunque sia il tuo ramo di sviluppo). (Il suffisso SNAPSHOT è importante, se usi Maven, poiché Maven tratta gli artefatti con versione SNAPSHOT in modo diverso rispetto ad altri.)

In realtà, penso che tu voglia istituire una politica di cambiare sempre e solo il numero di versione sul tuo ramo di produzione (quello da cui crei i rilasci) o sui rami che sono solo a scopo di rilascio (ad esempio, cambiando i numeri di versione) e che non hai intenzione di unire al ramo di sviluppo.

Non ho ancora usato questa strategia, ma ci stavo solo pensando, e penso che inizierò a provarlo.