Come faccio a recuperare / risincronizzare dopo che qualcuno spinge un rebase o un reset a un ramo pubblicato?
-
28-09-2019 - |
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?
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 congit checkout -b topic origin/master
, la storia della remota-trackingorigin/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 commitB3
,B2
,B1
e ora punta aB
, e la filialetopic
è stato avviato su di esso indietro quandoorigin/master
era aB3
.Questa modalità utilizza la reflog di
origin/master
per trovareB3
come punto di forchetta, in modo che iltopic
può essere rapportati in cima alla aggiornatoorigin/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"> Trovare il punto in cui un ramo (o qualsiasi storia che porta a Il comando " Ad esempio, se la storia sembrava dove: si cerca di trovare Internamente, abbiamo Git 2.1 (Q3 2014) aggiungerà rendere questa caratteristica più robusto a questo: vedi commettere 1e0dacd da John Keeping ( gestire correttamente lo scenario in cui sihanno la seguente topologia: dove: Il risultato corretto della Se la forcella-point non è identificato, quindi scegliere git merge-base
comando
--fork-point::
<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>
.
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.
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 B3
, 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)
". 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
".
johnkeeping
) C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
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
. 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
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.