Git pull dopo l'aggiornamento forzato


333

Ho appena eliminato alcuni impegni git rebasee ho fatto un git push --force(che è male, lo so).

Ora gli altri ingegneri del software hanno una storia diversa e quando lo fanno git pull, Git si fonderà. C'è un modo per risolvere questo problema, tranne fare un rm my-repo; git clone git@example.org:my-repo.git?

Ho bisogno di qualcosa di simile al contrario git push --force, ma git pull --forcenon ho dato i risultati sperati.


16
possono cancellare il loro ramo e ricrearlo anche loro, senza dover cancellare l'intero repository:git checkout master && git branch -D test && git checkout -b test origin/test
Florian Klein,


Risposte:


511

Per ricevere i nuovi commit

git fetch

Ripristina

È possibile reimpostare il commit per una filiale locale utilizzando git reset.

Per modificare il commit di una filiale locale:

git reset origin/master --hard

Fai attenzione, come dice la documentazione:

Reimposta l'indice e l'albero di lavoro. Qualsiasi modifica ai file tracciati nell'albero di lavoro da quando <commit> viene scartata.

Se desideri effettivamente conservare le modifiche apportate localmente, --softesegui invece un ripristino. Che aggiornerà la cronologia di commit per il ramo, ma non cambierà alcun file nella directory di lavoro (e potrai quindi eseguirne il commit).

rebase

Puoi riprodurre i tuoi commit locali sopra qualsiasi altro commit / ramo usando git rebase:

git rebase -i origin/master

Questo invocherà il rebase in modalità interattiva in cui puoi scegliere come applicare ogni singolo commit che non è nella cronologia su cui stai eseguendo il rebasing.

Se i commit che hai rimosso (con git push -f) sono già stati inseriti nella cronologia locale, verranno elencati come commit che verranno riapplicati: dovranno essere eliminati come parte del rebase o verranno semplicemente reinseriti nella cronologia per il ramo - e riapparire nella cronologia remota al prossimo push.

Utilizzare la guida git command --helpper maggiori dettagli ed esempi su uno dei comandi sopra (o altri).


2
@iblue scegli tra perdere tutte le modifiche, rimuovere la cronologia del commit ma mantenere le modifiche al file o tentare di applicare ogni commit in cima al nuovo head. L'opzione più semplice è probabilmente un ripristino software.
AD7,

1
@iblue Quando il tuo collega usa `git reabse origin / master ', e nel frattempo, ha già avuto un po' di commit prima, git scriverà il tuo commit sul retro del loro commit.
Tim

6
Vale la pena ricordare che se questo è per un ramo diverso:git reset origin/otherbranch --hard
bmaupin

Quindi, per chiarire, questo è uno : Opzione 1: reset --hard, o Opzione 2: reset --soft+ rebase, giusto?
PlasmaBinturong,

2
@PlasmaBinturong No. git reset --soft origin/mastermodificherà la cronologia di commit in modo che corrisponda alle differenze del telecomando e dello stage con il telecomando che verrà quindi eseguito il commit . Non ci sarebbe bisogno di rifarsi in quello scenario (e ti sarebbe stato impedito di farlo a causa delle modifiche non impegnate) perché non c'è differenza nella cronologia del commit. Le due opzioni vengono ripristinate o ripristinate , non una combinazione di entrambe. Per favore, fai una domanda se il tuo scenario è diverso da quello a cui ho risposto qui.
AD7

16

Questo non risolverà i rami che hanno già il codice che non vuoi in loro (vedi sotto per come farlo), ma se avessero estratto un ramo e ora vogliono che sia pulito (e non "in anticipo" di origin / some-branch) quindi semplicemente:

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Nota: puoi combinarli tutti mettendo && tra di loro

Nota2: Florian lo ha menzionato in un commento, ma chi legge i commenti quando cerca le risposte?

Nota 3: se si dispone di rami contaminati, è possibile crearne di nuovi in ​​base al nuovo "ramo stupido" e solo la scelta della ciliegia commette.

Ex:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

Ora la novità è la tua filiale senza gli extra (forse cattivi) impegni!


Questo è quello che volevo davvero. Qualcuno ha riformato il ramo principale (perché Dio sa quale motivo) ma non avevo cambiamenti locali che volevo impegnare o altro. Quindi tutto quello che dovevo fare era cancellare il mio ramo principale locale (che sembrava davvero strano) e fare di nuovo un checkout. Grazie!
Danilo Carvalho,

@ peter-Mortensen modifiche dovrebbe essere sostanziale secondo la stackoverflow.com/help/editing
Tom Prats

per l'ultimo passaggio, puoi anche usare git checkout -b base-branch origin/base-branchcongit checkout --track origin/base-branch
bluesmonk il

2

Tirare con rebase

Un pull regolare è fetch + merge, ma quello che vuoi è fetch + rebase. Questa è un'opzione con il pullcomando:

git pull --rebase

Lo uso sempre per ottenere l'ultimo codice dal master nel mio ramo di funzionalità senza avere tutti quei commit di unione nella cronologia.
herman,
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.