non può spingere al ramo dopo rebase


131

Usiamo git e abbiamo un ramo master e rami sviluppatore. Ho bisogno di aggiungere una nuova funzionalità e quindi reimpostare gli commit su master, quindi spingere master su server CI.

Il problema è che se ho conflitti durante rebase non posso spingere al mio ramo di sviluppatore remoto (su Github) dopo che il rebase è completo, fino a quando non tiro il mio ramo remoto. Ciò provoca commit duplicati. Quando non ci sono conflitti, funziona come previsto.

domanda: dopo il rebase e la risoluzione dei conflitti, come posso sincronizzare i rami degli sviluppatori locali e remoti senza creare commit duplicati

Impostare:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

MODIFICARE

Quindi sembra che questo interromperà il flusso di lavoro:

developer1 lavorando su myNewFeature developer2 lavorando su hisNewFeature utilizza entrambi master come ramo principale

developer2 unisce myNewFeature in hisNewFeature

developer1 ripristina, risolve i conflitti, quindi forza le spinte al ramo remoto per myNewFeature

un paio di giorni dopo, developer2, fonde di nuovo myNewFeature in newNew

Questo causerà agli altri sviluppatori l'odio per developer1?


non una soluzione ma solo un pensiero. chi è we? fai parte di una squadra di più di te? theydite (le persone che ne sanno più di me) che se condividete il codice di quanto non dovreste usare rebase. Perché non lo stai facendo git pulle git merge?
AdamT,

scusate, We = team di sviluppo
Matt,

1
quindi sì, probabilmente non dovresti ripetere il rebasing quando condividi il codice. che potrebbe force
indurti

oh scusa, quando dicono rewriting history, è unrebase
AdamT,

Come ha detto, è un ramo di sviluppo tutto suo, quindi non dovrebbe essere un problema a meno che non ci si aspettasse che qualcuno lo fondesse.
Learath2,

Risposte:


93

Innanzitutto, tu e le persone con cui stai lavorando devi concordare se un ramo tematico / di sviluppo è per lo sviluppo condiviso o solo il tuo. Altri sviluppatori sanno di non unirsi ai miei rami di sviluppo perché verranno riformulati in qualsiasi momento. Di solito il flusso di lavoro è il seguente:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Quindi, per rimanere aggiornato con il telecomando, farò quanto segue:

 git fetch origin
 git checkout master
 git merge --ff origin/master

Lo faccio per due motivi. Innanzitutto perché mi permette di vedere se ci sono cambiamenti remoti senza dover passare dal mio ramo di sviluppo. In secondo luogo è un meccanismo di sicurezza per assicurarsi che non sovrascriva eventuali modifiche non archiviate / impegnate. Inoltre, se non riesco a unirmi rapidamente all'unione del ramo principale, ciò significa che qualcuno ha riformulato il maestro remoto (per il quale devono essere gravemente frustati) o mi sono impegnato accidentalmente nel maestro e ho bisogno di ripulire la mia fine.

Quindi, quando il telecomando ha delle modifiche e sono passato rapidamente all'ultimo, mi rifarò:

git checkout devel0
git rebase master
git push -f origin devel0

Altri sviluppatori poi sanno che dovranno rifare i loro rami di sviluppo dal mio ultimo:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Il che si traduce in una storia molto più pulita:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Non unire gli impegni avanti e indietro per il tuo capriccio. Non solo crea commit duplicati e rende impossibile seguire la storia, ma è quasi impossibile trovare regressioni da una modifica specifica (motivo per cui stai usando il controllo versione in primo luogo, giusto?). Il problema che stai riscontrando è il risultato di fare proprio questo.

Inoltre, sembra che altri sviluppatori potrebbero impegnarsi nei rami di sviluppo. Puoi confermare questo?

L'unica volta in cui unire è quando il tuo ramo argomento è pronto per essere accettato master.

In una nota a margine. Se più sviluppatori si stanno impegnando nello stesso repository, dovresti prendere in considerazione la possibilità di nominare i rami per distinguere i rami di sviluppo degli sviluppatori. Per esempio:

git branch 'my-name/devel-branch'

Quindi tutti i rami degli argomenti degli sviluppatori risiedono all'interno del proprio set nidificato.


1
"Inoltre sembra che altri sviluppatori potrebbero impegnarsi nei rami di sviluppo. Puoi confermarlo?" SÌ sono ...
Matt,

Hai anche portato alla mia attenzione un altro problema. Lavorare tra l'ufficio e la casa. Faccio le fusioni in entrambi i posti e alla fine spingo in modo da poter riprendere da dove avevo interrotto. Quindi, quando è il momento di ribattezzarsi, tutti questi impegni creano confusione. Ho bisogno di trattare i miei rami come un solo ramo e rebase
Matt,

@Matt Sì, questi due problemi rovineranno davvero il tuo flusso di lavoro. Per la prima, comunicherei agli altri sviluppatori che solo il proprietario può impegnarsi con un nome ramificato (ad esempio "matt / devel"). IMHO, nessun sviluppatore dovrebbe impegnarsi comunque nello stesso ramo. Crea confusione. Per i successivi, il rebasing e la spinta forzata dovrebbero mantenere le due posizioni aggiornate.
Trevor Norris,

Bella risposta. Ho una domanda secondaria, perché stai usando la --forcebandiera quando lo fai git push -f origin devel0?
Nobita,

2
@Nobita Quando git pushnon è possibile avanzare rapidamente (ovvero la cronologia sha non corrisponde) è necessario forzare il push per sovrascrivere la cronologia precedente con la nuova cronologia generata da git rebase.
Trevor Norris,

50

Devi forzare la spinta quando hai spostato i commit più in basso lungo la linea git si aspetta che tu aggiunga commit alla punta del ramo. git push -f origin myNewFeaturerisolverà il tuo problema.

Suggerimento: sopra c'è un uso legittimo della forza che spinge. Non riscrivere mai la storia su un repository accessibile pubblicamente o molte persone ti odieranno.


1
Trovo questo il modo più ottimale per mantenere il flusso di lavoro.
Syed Priom,

1
Grazie compagno. Ho usato questo comando per forzare il mio ramo locale riformulato sullo stesso ramo remoto.
wei

11
usare git push --force-with-leaseè molto più sicuro che usaregit push --force

git push --force-with-lease origin HEAD- supponendo che il tuo ramo di destinazione sia già stato verificato
Lucaci Sergiu,

31

La cosa principale da tenere a mente qui è ciò che stanno facendo pull e rebase dietro le quinte.

Un tiro fondamentalmente farà due cose: recuperare e unire. Quando includi --rebase, farà un rebase anziché l'unione.

Un rebase è praticamente come mettere da parte tutte le modifiche locali da quando si è ramificato, inoltrare rapidamente il proprio ramo all'ultimo commit sulla destinazione e annullare le modifiche in ordine in alto.

(Questo spiega perché è possibile che vengano visualizzate più richieste di risoluzione dei conflitti quando si esegue una rebase rispetto all'unica risoluzione dei conflitti che si ottiene con una fusione. È possibile risolvere un conflitto su OGNI commit che viene riequilibrato per preservare altrimenti i propri commit. )

Non si desidera mai eseguire il push delle modifiche ridisegnate ai rami remoti poiché si tratta di riscrivere la cronologia. Ovviamente, non è mai un po 'forte in quanto ci sono quasi sempre delle eccezioni. Ad esempio, il caso in cui sia necessario mantenere una versione remota del repository locale per lavorare su un ambiente specifico.

Ciò richiederà a volte di modificare le modifiche reimpostate utilizzando la forza:

git push -f origin newfeature

O in alcuni casi il tuo amministratore potrebbe aver rimosso la possibilità di forzare, quindi è necessario eliminare e ricreare:

git push origin :newfeature
git push origin newfeature

In entrambi i casi devi essere assolutamente sicuro di sapere cosa stai facendo se qualcun altro sta collaborando con te sul tuo ramo remoto. Ciò può significare che inizialmente lavori insieme per unire e ridisegnare quelli in un formato di commit più gestibile appena prima di andare a padroneggiare e rimuovere il tuo ramo di lavoro.

Ricorda che puoi quasi sempre eseguire il fallback sul GC di Git sfruttando:

git reflog

Questo è un ENORME salvavita in quanto puoi ripristinare uno stato più stabile se ti perdi in tutta la tua gestione di conflitti / conflitti.


L'opzione di eliminazione e ricrea in precedenza ha funzionato bene per me. Nessuna forzatura consentita sul mio repository!
Simon Holmes,

2

È necessario eseguire una spinta forzata, ad es git push -f origin myNewFeature

Oh, e faresti meglio a essere dannatamente sicuro che le persone non basino nulla sul tuo ramo di sviluppo - di solito non dovresti pubblicare rami in cui stai riscrivendo la cronologia (o piuttosto non riscrivere la storia una volta pubblicata). Un modo sarebbe usare un nome di ramo come wip/myNewFeaturee poi menzionare che i wiprami saranno di volta in volta riformati per essere padroneggiati.


usare git push --force-with-leaseè molto più sicuro che usaregit push --force

@MrCholo Le persone non inizieranno a usarlo fino a quando git non aggiunge una breve opzione come -fper una normale spinta forzata :)
ThiefMaster

ah sì, l'ho usato in uno script automatizzato tho

2

La risposta generale che è già stata data - da usare git push -f origin myNewFeaturequando si spingono cambiamenti modificati - è un buon punto di partenza. Sto scrivendo questa risposta per affrontare la modifica relativa alla possibilità di interrompere il flusso di lavoro.

Se si assume che si sta andando ad essere utilizzando git pull --rebase ...(o qualche variazione su questo) seguito da una forza-push al ramo a distanza, quindi la cosa che rompe il flusso di lavoro nel tuo esempio è Developer2 si fonde myNewFeaturein hisNewFeature. Ha senso essere in grado di reimpostare il proprio ramo di funzionalità finché nessun altro sta lavorando su quel ramo, quindi sono necessarie regole per delimitare il territorio del ramo.

Puoi aggirare ciò a) stabilendo una regola da cui ti fondi sempre master, oppure b) creando un developramo collettivo , su cui basare il tuo myNewFeatureramo, e stabilendo una regola da cui ti fondi sempre develop. mastersarà quindi riservato solo alle pietre miliari o alle versioni (o comunque si desideri configurarlo) e developsarà dove si spinge ogni funzione quando è pronta per essere integrata in altri rami di funzionalità.

Credo che questa possa essere considerata una versione semplificata del flusso di lavoro di Gitflow.


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.