2011-01-19 23 views
12

a fondere le mie modifiche nei confronti di un maestro a monte, ho spesso ritrovo a fare la seguente:sovrascrittura e spingendo un Git Branch

git checkout somefeature 
git checkout -b integration 
git rebase master # resolving conflicts along the way 
git checkout somefeature 
git merge integration # or rebase, doesn't matter in this example 

io spesso trovo che la fusione del ramo integrazione di nuovo nel mio ramo caratteristica non riesce fare ad alcuni conflitti La prima domanda che ho è: "perché sta succedendo se il mio ramo di integrazione è un discendente di qualche caratteristica e ho già risolto i conflitti con il master upstream?"

Se ti stai chiedendo perché sto usando un ramo di integrazione, è per evitare di inquinare il mio ramo corrente con un'unione mezza fallita.

mia soluzione attuale è quella di fare questo:

git checkout integration 
git branch -f somefeature # overwrite the branch 

Il problema ora è che non riesco a spingere i miei cambiamenti di nuovo ad una filiale remota:

git push origin somefeature 
! [rejected]  somefeature -> somefeature (non-fast forward) 

Così ora devo togliere la filiale remota e ri-spingere le mie modifiche. Questo non può essere il modo ottimale per farlo, quindi mi chiedo "qual è il modo migliore per sovrascrivere un ramo e inviare le modifiche a un ramo remoto?"

risposta

15

Il problema è causato perché git rebase genera una nuova serie di commit che non discendono dal ramo somefeature, poi quando si tenta e unirli di nuovo in somefeature la risoluzione dei conflitti fatto durante il rebase non si applica. Se si dovesse semplicemente unire invece di rebase, ciò funzionerebbe come il commit di unione sarebbe discendere dal ramo somefeature.

In termini di push al ramo remoto è sufficiente utilizzare --force per far sì che il push abbia esito positivo, causando problemi a chiunque ne abbia una copia.

+3

Nota comunque che non dovresti mai cambiare i commit già pubblicati, poiché gli altri che lavorano con te si imbatteranno negli stessi problemi che hai, che hanno già commessi duplicati e incompatibili già nel loro repository. Il rebasing va bene fintanto che è solo locale, ma ribadire commit e ripubblicarli è malvagio - da qui l'errore "rifiutato" * di Git (è intelligente e nota che probabilmente stai facendo qualcosa di sbagliato). – poke

+0

Ah, stavo usando l'unione per comodità di risoluzione dei conflitti passo a passo senza considerare che i commit non sarebbero discendenti del ramo qualche caratteristica. Accettandolo come la vera risposta alla mia domanda. Grazie mille! – tmountain

0

Il tuo primo intervento è molto strano. Fai una copia di qualche caratteristica. Lo rifai contro il maestro. Poi torni a quella caratteristica e la fondi con l'equivoco rebased di se stessa. Questo non è il modo di fare le cose.

Non complicare le cose. Se vuoi che il ramo della funzione inizi da qualche altra parte (come l'ultimo master), basta ribasarlo.

Quindi premere con --force (o -f). Di 'a chiunque altro stia usando quel ramo di funzionalità che devono recuperare le modifiche e regolare tutto ciò che hanno localmente che non hanno ancora fatto.

L'unione è migliore nel caso in cui altri ci abbiano lavorato.

Spero che questo aiuti.

+1

Eh, era sotto l'impressione che fare una copia di qualche caratteristica e quindi unirla a quella del master sarebbe un modo semplice per unire due rami senza mescolare con uno degli originali. Suppongo che sia meglio solo fare un rebase standard. Grazie. – tmountain

+0

puoi invece unirlo. Stavi cercando di fare entrambe le cose. Questo era il problema. Spetta a te se vuoi unire per padroneggiare o rebase per padroneggiare. Uno produce una storia lineare, l'altro conserva il punto in cui si ramifica. La tua scelta. Avrai potenzialmente più conflitti da risolvere se prendi la route di rebase oltre a "spostare il formaggio di qualcuno" potenzialmente. –

4

È possibile utilizzare git merge -s recursive -Xtheirs, che risolverà automaticamente i conflitti a favore del ramo di integrazione. Tuttavia, ciò fa ancora una fusione e potrebbe non funzionare bene con i file in movimento e così via.

Tuttavia, dal momento che il tuo ramo è inserito, hai una ragione per cui vuoi mantenere la sua cronologia. Per ottenere il comportamento ideale desiderato, è possibile utilizzare la strategia "nostra" nel ramo dell'integrazione.

git checkout somefeature 
git checkout -b integration 
git rebase master # resolving conflicts along the way 
git merge -s ours somefeature # mark integration as superseding the somefeature branch 
git checkout somefeature 
git merge integration # this is now a fast-forward, no conflicts 
+0

Tuttavia, in generale, la soluzione di Nemo157 è migliore: basta utilizzare l'unione anziché rebase dall'inizio per i rami di funzionalità pubblicati in un repository non locale. È così che git è progettato per funzionare. –

+0

Non ero a conoscenza della strategia di unione "nostra". Questa sembra la soluzione che stavo cercando. Grazie! – tmountain