Il ramo Git si è discostato dopo il rebase


112

Ho ribasato localmente un ramo che era già stato inviato.

Git sta avvisando che il mio ramo e il telecomando sono divergenti e che:

"e hanno rispettivamente 109 e 73 commit diversi"

Il push del mio ramo risolverà questo problema, cioè è prevedibile dopo un rebase?


Ho lo stesso problema. Possiamo dire che "il modo giusto di fare" è ribasare il ramo locale e solo dopo spingere?
Mher Didaryan

Risposte:


154

Quando ribasate un ramo, dovete riscrivere i commit per ogni commit che si trova sopra i commit nel ramo su cui state ribasando. Questo perché una delle proprietà di un commit è il suo genitore (o genitori). Quando rebase, stai cambiando il genitore del commit locale più vecchio sul tuo ramo - e quindi cambiando gli hash di commit di tutti i tuoi commit locali, poiché questa modifica bolle in modo transitorio attraverso i commit.

Dato che avevi già eseguito il push del ramo, avresti dovuto unirti al ramo sorgente, invece di ribasarlo contro di esso. È possibile "forzare il push" del tuo nuovo ramo (usando il -fflag), ma un push normale non funzionerà, perché l'integrità della cronologia dei rami sarà disturbata. Se stai collaborando con altri in questo ramo, la spinta forzata è una cattiva idea, poiché causerà la confusione degli altri collaboratori quando la loro storia improvvisamente non corrisponde.

TL; DR - Se non stai collaborando, esegui il push del ramo utilizzando push -f. In tal caso, ripristina il ramo allo stato precedente e unisci invece il ramo di origine.


1
"Dato che avevi già eseguito il push del ramo, avresti dovuto unirti al ramo di origine" - perché?
Hammett

1
@HamiltonVerissimo Prima frase di Jason: "Quando rebase un ramo, devi riscrivere i commit per ogni commit che si trova sopra i commit nel ramo su cui stai ribasando." Anche se le modifiche acquisite nei commit "precedenti" hanno lo stesso contenuto logico, vengono applicate a una base diversa e quindi sono commit diversi con hash diversi. Se altri sviluppatori stanno lavorando dal ramo pre-ribasato, eseguire un git push -f sarebbe estremamente distruttivo per il loro flusso di lavoro. Pertanto, poiché questo ramo è stato trasferito a una fonte pubblica, avrebbe dovuto fondersi.
awolf

4
puoi anche usare push --force-with-lease se non sei sicuro che qualcun altro abbia già spinto qualcosa.
Console

1
@ jason-lebrun Non è lo svantaggio di unire le modifiche a monte che puoi sovrascrivere il tuo lavoro senza preavviso? I conflitti di unione vengono rilevati allo stesso modo del rebase? Ad esempio, se rimuovo una sezione da un file nel mio ramo perché non è più necessario, ma qualcun altro ha apportato una modifica banale alla stessa sezione a monte, come rimuovere alcuni spazi bianchi o un'azione di ricerca / sostituzione globale, non lo farebbe unendo quello in cima al mio ramo sostituire la mia cancellazione con la loro versione banalmente cambiata?
Chris Bloom

1
Unire l'altro ramo al tuo non è una cattiva idea? Ad esempio, l'unione del master in un ramo di funzionalità: ciò non creerà un nuovo commit per quello? Ciò non si tradurrà in un commit aggiuntivo una volta che questo ramo di funzionalità si unirà al master in seguito?
Ross

55

Tutti i tuoi commit hanno cambiato ID, quindi la deviazione non è veramente una divergenza.

Per risolvere il tuo problema devi sovrascrivere il tuo ramo remoto:

git push -f origin experiment

http://git-scm.com/book/ch3-6.html

Spiegazione:

Guarda come in questa immagine C3 non è messo come C3 dopo il rebase, ma come C3 '. Questo perché non è esattamente C3, ma ha tutte le modifiche al codice.

rebase

In quest'altra immagine si ottiene l'immagine di ciò che si vede un rebase quando è coinvolto un telecomando e perché c'è un diversivo.

divergere e git push

In ogni caso, dopo aver eseguito la spinta forzata, ti dirà che ha fatto un (aggiornamento forzato), dovresti stare bene a quel punto.

Controlla il link in alto e cerca "git push --force". Vedrai una spiegazione più dettagliata.


3
Sì. Immagino che questo risolva il problema. Tuttavia, il push forzato potrebbe non funzionare quando lavori con un team quando il tuo push potrebbe sovrascrivere qualsiasi lavoro recente spinto da altri. Ho ragione?
Hari Krishna Ganji

Potrebbe non avere gli effetti desiderati. Assicurati di unire le modifiche "avanti veloce" prima di eseguire il rebase.
mimoralea

1

Ho avuto successo con il rebase divergere per una spinta facendo quanto segue:

git checkout mybranch
git pull
git push origin mybranch

L'attrazione ha risolto il divario.

PRIMA del tiro

Your branch and 'origin/mybranch' have diverged,
and have 2 and 1 different commit(s) each, respectively.

Uscita PULL

Unione realizzata da ricorsivo. miopercorso / miofile.py | 12 +++++++++++ - 1 file modificato, 11 inserimenti (+), 1 eliminazioni (-)

DOPO tirare

Il tuo ramo è davanti a "origin / mybranch" di 3 commit.

DOPO PUSH

mybranch è 3 prima del ramo ha ancora un messaggio di unione di richiesta pull aperto aggiunto alla cronologia di commit Unisci ramo mybranch di remoto in mybranch

Presumo che questo sia probabilmente ciò che fa la spinta della forza e non l'ho verificato.

Come hanno già detto gli altri, evita un rebase se hai già una richiesta pull aperta. Fornisco questo esempio come qualcosa che ha funzionato per me.


1

Questo può essere risolto senza forzare il push ribasando il ramo di destinazione nel ramo locale corrente, passando al ramo di destinazione e quindi ribasando il ramo locale nel ramo di destinazione. Questo non diverge poiché i commit che potrebbero mancare vengono aggiunti e non è necessario crearli più. Esempio per una spiegazione più semplice:

  1. si sviluppa il ramo principale
  2. Esegui il checkout di una nuova funzionalità di ramo / doing_stuff
  3. Un membro del team spinge un nuovo impegno per lo sviluppo

Se NON hai aggiornato il tuo ramo di sviluppo, allora un "git checkout Develop" && "git rebase feature / doing_stuff" funzionerà correttamente poiché nessun commit è stato aggiunto dal checkout. Tuttavia, se hai controllato lo sviluppo e tirato giù il nuovo commit, vedrai questa divergenza se provi a rebase a causa della visualizzazione di un nuovo commit. Una soluzione semplice senza forzature (di solito non è una buona idea in un ambiente di squadra) è:

  1. git checkout feature / doing_stuff
  2. git rebase sviluppare
  3. sviluppo di git checkout
  4. git rebase feature / doing_stuff

Il rebase dal passaggio 2 porta il commit mancante nella feature / doing_stuff, quindi quando arriva il passaggio 4 è aggiornato e non è necessario creare un nuovo commit per la modifica.

Questa è una soluzione che so funziona perché mi sono imbattuto in questo e ho eseguito i passaggi precedenti per spingere con successo lo sviluppo senza forzare. Lavoro in un team di oltre 50 sviluppatori, quindi è vietato forzare il push a parte i miei rami di test, quindi ho dovuto trovare una soluzione.

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.