Come faccio a recuperare / risincronizzare dopo che qualcuno spinge un rebase o un reset a un ramo pubblicato?

StackOverflow https://stackoverflow.com/questions/4084868

Domanda

Abbiamo tutti sentito che uno dovrebbe mai rebase pubblicato il lavoro, che è pericoloso, ecc, tuttavia, non ho visto nessun ricette inviati per come affrontare la situazione nel caso in cui un rebase è pubblicata .

Ora, si noti che questo è solo veramente fattibile se il repository viene clonato solo da un gruppo noto (e preferibilmente piccolo) di persone, in modo che chi spinge il rebase o ripristino può avvisare tutti gli altri che avranno bisogno di prestare attenzione la prossima volta che fetch (!).

Una soluzione ovvia che ho visto funziona se non si hanno commit locali foo e diventa ricalcolato:

git fetch
git checkout foo
git reset --hard origin/foo

Questo sarà semplicemente buttare via lo stato locale della foo a favore della sua storia come per il repository remoto.

Ma come si fa a trattare con la situazione se uno ha commesso sostanziali modifiche locali su quel ramo?

È stato utile?

Soluzione

Tornando in sincronia dopo un rebase spinto non è poi tanto complicato in molti casi.

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

Ie. prima di impostare un segnalibro per cui la filiale remota origine era, quindi si utilizza che di riprodurre i propri commit locali da quel punto in avanti sul ramo remoto ricalcolato.

rebasing è come la violenza: se non risolve il problema, è solo bisogno di più di esso. ☺

E 'possibile fare questo senza il segnalibro, naturalmente, se si guarda il origin/foo pre-rebase impegnarsi ID, e l'uso che.

Questo è anche come si tratta con la situazione in cui si è dimenticato di fare un segnalibro prima recupero. Nulla è perduto - è sufficiente controllare la reflog per la filiale remota:

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

Questo stamperà l'ID che origin/foo indicò prima della più recente del recupero ha cambiato la sua storia commit.

Si può poi semplicemente

git rebase --onto origin/foo $commit foo

Altri suggerimenti

Direi che il recupero da monte rebase sezione della git- uomo rebase pagina copre praticamente tutto di questo.

E 'davvero diverso da recuperare dal tuo rebase - si sposta un ramo, e rebase tutti i rami che avevano nella loro storia sulla sua nuova posizione

.

A partire da git 1.9 / 2.0 Q1 2014, non sarà necessario per segnare il tuo origine ramo precedente prima rebasing sul ramo monte riscritto, come descritto in Aristotele Pagaltzis 's risposta :
Vedere commettere 07d406b e commettere d96855f :

  

Dopo aver lavorato sul ramo topic creata con git checkout -b topic origin/master, la storia della remota-tracking origin/master ramo potrebbe essere stato riavvolto e ricostruito, portando ad una storia di questa forma:

                   o---B1
                  /
  ---o---o---B2--o---o---o---B (origin/master)
          \
           B3
            \
             Derived (topic)
  

dove origin/master usato per indicare a commit B3, B2, B1 e ora punta a B, e la filiale topic è stato avviato su di esso indietro quando origin/master era a B3.

     

Questa modalità utilizza la reflog di origin/master per trovare B3 come punto di forchetta, in modo che il topic può essere rapportati in cima alla aggiornato origin/master da:

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

Questo è il motivo per cui la href="http://git-scm.com/docs/git-merge-base" rel="nofollow noreferrer"> git merge-base comando

--fork-point::
  

Trovare il punto in cui un ramo (o qualsiasi storia che porta a <commit>) biforcuta da un altro ramo (o qualsiasi riferimento) <ref>.
  Questo non si limita a guardare per l'antenato comune delle due commit, ma tiene conto anche della reflog di <ref> per vedere se la storia che porta a <commit> biforcuta da una precedente incarnazione della filiale <ref> .


  

Il comando "git pull --rebase" calcola il punto forcella del ramo essendo riassegnata utilizzando le voci reflog del ramo "base" (tipicamente un ramo remoto-tracking) lavoro del ramo è basata su, al fine di far fronte al caso in che il ramo "base" è stato riavvolto e ricostruito.

Ad esempio, se la storia sembrava dove:

  
      
  • la punta corrente del ramo "base" è al B, ma in precedenza fetch ha osservato che la sua punta usato per essere B3 e quindi B2 e poi B1   prima di arrivare alla corrente impegnarsi, e
  •   
  • il ramo di essere rapportati cima alle ultime "base" si basa su commettere B3,
  •   
     

si cerca di trovare B3 passando attraverso l'uscita di "git rev-list --reflog base" (vale a dire B, B1, B2, B3) finché non trova un commit che è un antenato della punta corrente "Derived (topic)".

     

Internamente, abbiamo get_merge_bases_many() che possono calcolare questo con un solo movimento.
  Vorremmo una fusione-base tra Derived e un'unione fittizia commit che si tradurrebbe fondendo tutte le punte storiche di "base (origin/master)".
  Quando tale commettere esistono, dovremmo ottenere un unico risultato, che corrisponde esattamente una delle voci reflog di "base".


Git 2.1 (Q3 2014) aggiungerà rendere questa caratteristica più robusto a questo: vedi commettere 1e0dacd da John Keeping (johnkeeping)

gestire correttamente lo scenario in cui sihanno la seguente topologia:

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

dove:

  • B' è una versione fissa-up di B che non è PATCH-identico B;
  • C* e D* sono patch-identici rispettivamente C e D e conflitti testualmente, se applicata in modo sbagliato;
  • E dipende testualmente sul D.

Il risultato corretto della git rebase master dev è che B è identificato come la forcella punto di dev e master, cosicché C, D, E sono i commit che devono essere riprodotti su master; ma C e D sono patch-identici C* e D* e così può essere eliminato, in modo che il risultato finale è:

o --- B' --- C* --- D* --- E  <- dev

Se la forcella-point non è identificato, quindi scegliere B su un ramo contenente risultati B' in un conflitto e se i commit di patch identiche non sono identificati correttamente poi scegliendo C su un ramo contenente D (o equivalentemente D*) determina un conflitto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top