In Git, la modifica di un commit pre-pull storico dopo il pull provoca una divergenza dall'origine
Domanda
Nel seguente scenario:
- Effettua i commit A, B, C
- Tira, ottieni i commit D, E
- Fai più commit F, G, H, ...
- Renditi conto che devi modificare B
- Modifica B utilizzando
git rebase -i
Egit commit --amend
Ora git status
dice:
Your branch and 'origin/master' have diverged.
Come dovrei risolvere questo problema?
Nota:Non ho spinto;questo non ha niente a che fare con la spinta.
Nota:Tirare semplicemente di nuovo non risolve il problema;semplicemente unisce nuovamente i commit D, E sopra quello che ho già (nonostante D, E sia già presente nella cronologia), il che ha anche l'effetto collaterale di produrre conflitti superflui.
Per approfondire, una risposta di seguito suggerisce che la storia ora è:
- A - B' - C' - F' - G' - H' (master)
\
D - E (origin/master)
Questo non è del tutto corretto, in realtà è:
- A - B' - C' - D(?) - E(?) - F' - G' - H' (master)
\
D - E (origin/master)
Quindi, il mio problema.mi piacerebbe che fosse:
- A - B' - C' - F' - G' - H' (master)
\ /
D - E (origin/master)
Soluzione 2
Nota:Non accetterò la mia risposta per un po' perché sono sinceramente curioso di conoscere altri (migliori) approcci.
Il modo in cui ne sono uscito non è stato affatto elegante:
# stash F, G, H - can't simply reorder them before D, E since they depend a lot on D, E
for i in {1..3}; do git reset HEAD^; git stash; done
# wipe out the weird non-merge D and E commits
git reset --hard HEAD~2
# pull to merge D, E again
git pull
# restore F, G, H
for i in {1..3}; do git stash pop; git commit -a; done
Altri suggerimenti
Immagino che tu non abbia usato il file -p
opzione per git rebase, il che significa che il pull che hai fatto, unendo i commit D ed E, è stato cancellato.Se questo è tutto quello che è successo, è semplice:basta tirare di nuovo.Se questo è quello che è successo, la tua cronologia sarà simile a questa:
- A - B' - C' - F' - G' - H' (master)
\
D - E (origin/master)
Ecco la tua divergenza!
Se tu fatto preservare l'unione, molto probabilmente è solo perché nel frattempo qualcosa di nuovo è stato spinto all'origine:
- A - B' - C' - X' - F' - G' - H' (master)
\ /
D - E -------- - Z (origin/master)
e quindi la soluzione, ancora una volta, sarebbe tirare.
Se, tuttavia, hai inviato qualcosa contenente il commit B originale, non avresti dovuto eseguire il rebase.Questo sarà Sempre causare divergenze, e non è una cosa divertente.La tua cronologia sarebbe simile a questa:
B' - C' - F' - G' - H' (master)
/
- A - B - C - X - F - G - H (origin/master)
\ /
D - E ------
È un fatto fondamentale della progettazione di git che lo SHA1 di un commit dipenda dallo SHA1 del suo genitore, e quindi dall'intera catena di ascendenza.Questo è il motivo per cui dopo i rebase ho messo un "prime" su tutto.Anche se non hai modificato il contenuto di C, il commit viene modificato.(L'altra possibilità, che tu abbia preservato l'unione e spinto, dovrebbe essere deducibile come una combinazione delle ultime due immagini.)