Come posso usare git rebase senza richiedere un push forzato?


92

Nel tentativo di raggiungere il git nirvana, sto passando la giornata a imparare come sfruttare il rebase per le situazioni in cui attualmente mi unisco.

Quando eseguo quello che considero un flusso git 101 (che spiegherò di seguito), devo farlo push --forcequando rimetto le mie modifiche all'origine.

Non sono l'unico - so che questo è un terreno coperto (vedere 1 , 2 , 3 , 4 , 5 ) e capisco le ragioni tecniche per cui è necessaria una forza. Il mio problema è questo --- ci sono molti (molti) post di blog che cantano le lodi di rebase e come ha cambiato le loro vite (vedi 1 , 2 , 3 , 4 per elencarne alcuni), ma nessuno di loro menziona che push --forcefa parte di il loro flusso. Tuttavia, quasi tutte le risposte alle domande di stackoverflow esistenti dicono cose come "sì, se vuoi riformulare, devi usare push --force".

Dato il numero e la religiosità dei sostenitori del rebase, devo credere che l'uso di "push --force" non sia una parte intrinseca di un flusso di rebase, e che se uno deve spesso forzare le loro spinte, sta facendo qualcosa di sbagliato .

push --forceè una brutta cosa .

Quindi ecco il mio flusso. In che modo potrei ottenere gli stessi risultati senza una forza?

Semplice esempio

Due rami:

  • v1.0 - un ramo di rilascio, contiene solo patch
  • master - tutto per la prossima major release.

Ho alcuni commit di patch e alcuni commit per la prossima versione.

premerge

Vorrei incorporare le patch nel mio master in modo che non vadano perse per la prossima versione. Pre-illuminazione, avrei semplicemente:

git checkout master
git merge v1.0

Ma ora ci sto provando

git checkout master
git rebase v1.0

Quindi ora sono qui:

inserisci qui la descrizione dell'immagine

Tempo per:

git push

Niente da fare.

Risposte:


43

Il rebasing è un ottimo strumento, ma funziona meglio quando lo usi per creare unioni in avanti veloce per i rami di argomento sul master. Ad esempio, potresti riformulare il tuo ramo add-new-widget contro master:

git checkout add-new-widget
git rebase -i master

prima di eseguire una fusione in avanti veloce del ramo nel master. Per esempio:

git checkout master
git merge --ff-only add-new-widget

Il vantaggio di questo è che la tua cronologia non avrà molti commit di unione complessi o conflitti di unione, perché tutte le tue modifiche verranno ribasate sulla punta del master prima dell'unione. Un vantaggio secondario è che hai ribasato, ma non devi usarlo git push --forceperché non stai rovinando la cronologia sul ramo principale.

Questo non è certamente l'unico caso d'uso per rebase, o l'unico flusso di lavoro, ma è uno degli usi più sensati che ho visto. YMMV.


4
Grazie CG, penso che "usalo per creare unioni in avanti veloce" sia la chiave. Non si applica al mio caso precedente in cui ho due rami attivi: un ramo di sviluppo e un ramo di rilascio, ma sembra applicarsi molto bene per i rami di argomenti temporanei che sono necessari solo per un periodo di tempo limitato, e quindi possono essere eliminati una volta uniti. Grazie ancora.
Roy Truelove

1
Lo capisco, ma la domanda originale rimane. Penso che la risposta effettiva sia quella data da @Fabien Quatravaux
IsmailS

4
Beh, dovresti comunque forzare il push del ramo 1.0, no? Almeno, è così che le cose tendono a finire per me tutto il tempo. Il metodo Fabiens impedirebbe che ciò accada.
joerx

23

@CodeGnome ha ragione. Non dovresti ribasare il master sul ramo v1.0 ma il ramo v1.0 sul master, questo farà la differenza.

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

Crea un nuovo ramo che punta alla v1.0, sposta quel nuovo ramo sopra il master e quindi integra la nuova versione delle patch V1.0 nel ramo master. Finirai con qualcosa del tipo:

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

Questo modo di usare rebase è consigliato dalla documentazione ufficiale di git .

Penso che tu abbia ragione git push --force: dovresti usarlo solo se hai commesso un errore e hai spinto qualcosa che non volevi.


Penso che questa sia la migliore risposta per il problema specifico nel PO. Si crea un ramo di unione temporaneo e si ribassa su quello, quindi si unisce al master e si invia all'origine. Il ramo temporaneo non deve essere inviato all'origine. L'unico consiglio aggiuntivo che darei è di avere un ramo di sviluppo o qa in cui il codice unito / riassunto può essere qualificato. Dopo la qualificazione, questo codice verrebbe quindi unito solo ff al master. Ciò consente un facile hotfix se il processo di qualificazione richiede troppo tempo. Questo è fondamentalmente il processo "git flow".
Javid Jamae

Grazie Fabien, ottima risposta. Per quelli di noi che vogliono solo integrare le modifiche mastere non si preoccupano di unire il ramo delle funzionalità stesso, questo può essere fatto con:git checkout my-branch; git rebase master; git checkout master; git merge my-branch
Siavas

17

Devi forzare il push se rebase e hai già pubblicato le tue modifiche, giusto?

Uso il rebase un intero gruppo, ma pubblico su qualcosa di privato in cui un force push non ha importanza (ad esempio: il mio clone su GitHub, come parte di una richiesta pull), o rebase prima di spingere per la prima volta.

Questo è il cuore del flusso di lavoro in cui usi il rebase, ma non forzare molto il push: non pubblicare le cose finché non sono pronte, non rebase dopo aver eseguito il push.


Grazie Dan. Potresti farmi sapere come si dovrebbe ottenere quanto sopra? Non è questo uno scenario in cui si applica il rebase?
Roy Truelove

2
Se si isola tutto il lavoro in rami di argomento, viene creato un buon scenario per il rebase. Hai rebaseappena inserito le modifiche nel tuo ramo di argomento, ma quando hai completato le modifiche di quel ramo, tumerge quel ramo, torni nel ramo di sviluppo principale.
redhotvengeance

1
Il problema è che hai pubblicato il ramo, quindi devi forzare il push al repository. Devi rinunciare a uno dei due: pubblicare nel modo in cui lo fai o ribasare. Scusate.
Daniel Pittman

Sembra che il rebase non funzioni per questo scenario. v1.0 non è un topic branch, è un release branch, quindi non morirà mai e dovrà essere pubblicato.
Roy Truelove

5

Penso che ci sia un buon caso d'uso per questo modello rebase-then-force-push che non è il risultato di un push errato: lavorare su un ramo di funzionalità da solo da più posizioni (computer). Lo faccio spesso, poiché a volte lavoro in ufficio sul mio desktop, e talvolta da casa / dal sito del cliente sul mio laptop. Di tanto in tanto ho bisogno di rebase per stare al passo con il ramo principale e / o per rendere più pulite le fusioni, ma devo anche forzare il push quando lascio una macchina per andare a lavorare su un'altra (dove mi limito a tirare). Funziona come un incantesimo, purché io sia l'unico a lavorare sul ramo.


2
Ho lo stesso flusso di lavoro (lavorando da più computer / posizioni). Quindi, supponiamo che tu stia lavorando su un ramo dell'argomento chiamato "mytopic". Fintanto che ribassi sempre un ramo usa e getta locale (che è semplicemente un ramo di mytopic) su "master" e poi lo unisci di nuovo in mytopic, non devi mai forzare il push. OP ha uno scenario leggermente diverso, quindi in un caso come questo potrebbe essere necessaria una spinta forzata. Tuttavia, penso che OP stia ribasando nel modo sbagliato: se lo facesse come ho descritto, non sarebbe necessaria alcuna spinta forzata.
bwv549

3

Ecco cosa uso (supponendo che il nome del tuo ramo sia foobar ):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work

2
Il maestro ribasatore sembra strano.
Emil Vikström

2
gitnon è privo di personalità
profumato il

1
git merge -s ours origin/<branch>è stato ciò che ha risolto per noi
Max

0

tl; dr si fonde con rami condivisi, rebase con rami individuali. --force-with-leaseè un'alternativa più sicura alla forza e dovrebbe aiutarti a raggiungere detto git nirvana senza la natura distruttiva della forza.

Una regola pratica generale che ho visto funzionare per i flussi di lavoro di vari team è quella di utilizzare mergeper rami condivisi (cioè, master o sviluppo) e utilizzare rebasequando si lavora sul proprio ramo di funzionalità. Ecco un tipico ciclo di vita di un ramo di funzionalità

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

Una semplice versione inglese di ciò che abbiamo fatto qui:

  1. Creato un nuovo ramo del master
  2. Fatto il lavoro sul ramo e inviato a remoto
  3. ribasato da master
  4. Spingi il lavoro in remoto con force-with-lease
  5. fondersi nel master con un log git molto pulito, riducendo l'ingombro di più unioni dal nostro ramo condiviso per fare in modo che il nostro ramo "raggiunga" l'ultimo master (ramo condiviso)

Il quarto passo è VERAMENTE importante e uno dei motivi principali per cui ho iniziato a sostenere l'uso del rebase. force-with-leasecontrolla il telecomando per vedere se sono stati aggiunti nuovi commit. Se tuogit push stato dimostrato di essere distruttivo, non spingerà!

Spero che questo dia a qualcuno più fiducia nell'usare rebase.

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.